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 ( 6104e1...48a667 )
by Baptiste
02:19
created

Sequence::foreach()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
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 290
    public function __construct(...$values)
24
    {
25 290
        $this->values = $values;
26 290
        $this->size = count($values);
27 290
    }
28
29
    /**
30
     * {@inheritdoc}
31
     */
32 56
    public function size(): int
33
    {
34 56
        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 132
    public function toPrimitive()
121
    {
122 132
        return $this->values;
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128 48
    public function get(int $index)
129
    {
130 48
        if (!$this->has($index)) {
131 6
            throw new OutOfBoundException;
132
        }
133
134 42
        return $this->values[$index];
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 52
    public function has(int $index): bool
141
    {
142 52
        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
            $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 6
    public function first()
251
    {
252 6
        return $this->values[0];
253
    }
254
255
    /**
256
     * {@inheritdoc}
257
     */
258 6
    public function last()
259
    {
260 6
        return $this->values[$this->size() - 1];
261
    }
262
263
    /**
264
     * {@inheritdoc}
265
     */
266 98
    public function contains($element): bool
267
    {
268 98
        return in_array($element, $this->values, true);
269
    }
270
271
    /**
272
     * {@inheritdoc}
273
     */
274 40
    public function indexOf($element): int
275
    {
276 40
        $index = array_search($element, $this->values, true);
277
278 40
        if ($index === false) {
279 2
            throw new ElementNotFoundException;
280
        }
281
282 38
        return $index;
283
    }
284
285
    /**
286
     * {@inheritdoc}
287
     */
288 4
    public function indices(): StreamInterface
289
    {
290 4
        $indices = new Stream('int');
291
292 4
        foreach ($this->values as $index => $value) {
293 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...
294
        }
295
296 4
        return $indices;
297
    }
298
299
    /**
300
     * {@inheritdoc}
301
     */
302 2
    public function map(callable $function): SequenceInterface
303
    {
304 2
        return new self(...array_map($function, $this->values));
305
    }
306
307
    /**
308
     * {@inheritdoc}
309
     */
310 4
    public function pad(int $size, $element): SequenceInterface
311
    {
312 4
        return new self(...array_pad($this->values, $size, $element));
313
    }
314
315
    /**
316
     * {@inheritdoc}
317
     */
318 2
    public function partition(callable $predicate): MapInterface
319
    {
320 2
        $truthy = [];
321 2
        $falsy = [];
322
323 2
        foreach ($this->values as $value) {
324 2
            if ($predicate($value) === true) {
325 2
                $truthy[] = $value;
326
            } else {
327 2
                $falsy[] = $value;
328
            }
329
        }
330
331 2
        return (new Map('bool', SequenceInterface::class))
332 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...
333 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...
334
    }
335
336
    /**
337
     * {@inheritdoc}
338
     */
339 34
    public function slice(int $from, int $until): SequenceInterface
340
    {
341 34
        return new self(...array_slice(
342 34
            $this->values,
343
            $from,
344 34
            $until - $from
345
        ));
346
    }
347
348
    /**
349
     * {@inheritdoc}
350
     */
351 4
    public function splitAt(int $index): StreamInterface
352
    {
353 4
        return (new Stream(SequenceInterface::class))
354 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...
355 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...
356
    }
357
358
    /**
359
     * {@inheritdoc}
360
     */
361 18
    public function take(int $size): SequenceInterface
362
    {
363 18
        return $this->slice(0, $size);
364
    }
365
366
    /**
367
     * {@inheritdoc}
368
     */
369 4
    public function takeEnd(int $size): SequenceInterface
370
    {
371 4
        return $this->slice($this->size() - $size, $this->size());
372
    }
373
374
    /**
375
     * {@inheritdoc}
376
     */
377 22
    public function append(SequenceInterface $seq): SequenceInterface
378
    {
379 22
        return new self(...$this->values, ...$seq->toPrimitive());
380
    }
381
382
    /**
383
     * {@inheritdoc}
384
     */
385 6
    public function intersect(SequenceInterface $seq): SequenceInterface
386
    {
387 6
        return new self(...array_intersect($this->values, $seq->toPrimitive()));
388
    }
389
390
    /**
391
     * {@inheritdoc}
392
     */
393 10
    public function join(string $separator): Str
394
    {
395 10
        return new Str(implode($separator, $this->values));
396
    }
397
398
    /**
399
     * {@inheritdoc}
400
     */
401 172
    public function add($element): SequenceInterface
402
    {
403 172
        $values = $this->values;
404 172
        $values[] = $element;
405
406 172
        return new self(...$values);
407
    }
408
409
    /**
410
     * {@inheritdoc}
411
     */
412 6
    public function sort(callable $function): SequenceInterface
413
    {
414 6
        $values = $this->values;
415 6
        usort($values, $function);
416
417 6
        return new self(...$values);
418
    }
419
420
    /**
421
     * {@inheritdoc}
422
     */
423 44
    public function reduce($carry, callable $reducer)
424
    {
425 44
        return array_reduce($this->values, $reducer, $carry);
426
    }
427
}
428