Passed
Push — 1.x ( d64718...5dddf6 )
by Ulises Jeremias
02:21
created

Sequenceable::concat()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
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 OverflowException;
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
    use Collection;
35
    use Sort {
36
        Sort::heapSort as heapSortWithCallback;
37
        Sort::heapSorted as heapSortedWithCallback;
38
    }
39
40
    /**
41
     * @inheritDoc
42
     */
43
    public static function fromItems(Traversable $array): SequenceableInterface
44
    {
45
        // We can only do it this way if we can count it
46
        if ($array instanceof Countable) {
47
            $sfa = new SplFixedArray(count($array));
48
49
            foreach ($array as $i => $elem) {
50
                $sfa[$i] = $elem;
51
            }
52
53
            return new static($sfa);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new static($sfa) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with $sfa. ( Ignorable by Annotation )

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

53
            return /** @scrutinizer ignore-call */ new static($sfa);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
54
        }
55
56
        // If we can't count it, it's simplest to iterate into an array first
57
        return static::fromArray(iterator_to_array($array));
58
    }
59
60
    /**
61
     * @inheritDoc
62
     */
63
    public static function fromArray(array $array): SequenceableInterface
64
    {
65
        return new static(SplFixedArray::fromArray($array));
0 ignored issues
show
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with SplFixedArray::fromArray($array). ( Ignorable by Annotation )

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

65
        return /** @scrutinizer ignore-call */ new static(SplFixedArray::fromArray($array));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug Best Practice introduced by
The expression return new static(SplFix...ray::fromArray($array)) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
66
    }
67
68
    /**
69
     * @inheritDoc
70
     */
71
    public function copy(): CollectionInterface
72
    {
73
        return static::fromArray($this->toArray());
74
    }
75
76
    /**
77
     * @inheritDoc
78
     */
79
    public function contains(...$values): bool
80
    {
81
        foreach ($values as $value) {
82
            if (!$this->find($value)) {
83
                return false;
84
            }
85
        }
86
87
        return true;
88
    }
89
90
    /**
91
    * @inheritDoc
92
    */
93
    public function first()
94
    {
95
        if ($this->isEmpty()) {
96
            throw new UnderflowException();
97
        }
98
99
        return $this[0];
100
    }
101
102
    /**
103
     * @inheritDoc
104
     */
105
    public function get(int $index)
106
    {
107
        if (! $this->validIndex($index)) {
0 ignored issues
show
Bug introduced by
It seems like validIndex() 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

107
        if (! $this->/** @scrutinizer ignore-call */ validIndex($index)) {
Loading history...
108
            throw new OutOfRangeException();
0 ignored issues
show
Bug introduced by
The type Mbh\Collection\Traits\OutOfRangeException was not found. Did you mean OutOfRangeException? If so, make sure to prefix the type with \.
Loading history...
109
        }
110
111
        return $this[$index];
112
    }
113
114
    /**
115
     * @inheritDoc
116
     */
117
    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

117
    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...
118
    {
119
        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

119
        if (! $this->validIndex($index) && $index !== count(/** @scrutinizer ignore-type */ $this)) {
Loading history...
120
            throw new OutOfRangeException();
121
        }
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function last()
128
    {
129
        if ($this->isEmpty()) {
130
            throw new UnderflowException();
131
        }
132
133
        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

133
        return $this[count(/** @scrutinizer ignore-type */ $this) - 1];
Loading history...
134
    }
135
136
    /**
137
     * Pushes all values of either an array or traversable object.
138
     */
139
    private function pushAll($values)
140
    {
141
        foreach ($values as $value) {
142
            $this[] = $value;
143
        }
144
145
        $this->checkCapacity();
0 ignored issues
show
Bug introduced by
It seems like checkCapacity() 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

145
        $this->/** @scrutinizer ignore-call */ 
146
               checkCapacity();
Loading history...
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151
    public function push(...$values)
152
    {
153
        $this->pushAll($values);
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    public function map(callable $callback): SequenceableInterface
160
    {
161
        $count = 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

161
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
162
        $sfa = new SplFixedArray($count);
163
164
        for ($i = 0; $i < $count; $i++) {
165
            $sfa[$i] = $callback($this[$i], $i, $this);
166
        }
167
168
        return new static($sfa);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new static($sfa) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with $sfa. ( Ignorable by Annotation )

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

168
        return /** @scrutinizer ignore-call */ new static($sfa);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
169
    }
170
171
    /**
172
     * @inheritDoc
173
     */
174
    public function walk(callable $callback): SequenceableInterface
175
    {
176
        foreach ($this as $i => $elem) {
177
            $callback($elem, $i, $this);
178
        }
179
180
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
181
    }
182
183
    /**
184
     * @inheritDoc
185
     */
186
    public function filter(callable $callback): SequenceableInterface
187
    {
188
        $count = 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

188
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
189
        $sfa = new SplFixedArray($count);
190
        $newCount = 0;
191
192
        foreach ($this as $elem) {
193
            if ($callback($elem)) {
194
                $sfa[$newCount++] = $elem;
195
            }
196
        }
197
198
        $sfa->setSize($newCount);
199
        return new static($sfa);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new static($sfa) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with $sfa. ( Ignorable by Annotation )

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

199
        return /** @scrutinizer ignore-call */ new static($sfa);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
200
    }
201
202
    /**
203
     * @inheritDoc
204
     */
205
    public function reduce(callable $callback, $accumulator = null)
206
    {
207
        foreach ($this as $i => $elem) {
208
            $accumulator = $callback($accumulator, $elem, $i, $this);
209
        }
210
211
        return $accumulator;
212
    }
213
214
    /**
215
     * @inheritDoc
216
     */
217
    public function join(string $token = ',', string $secondToken = null): string
218
    {
219
        $str = "";
220
        if ($secondToken) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $secondToken of type null|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
221
            foreach ($this as $i => $elem) {
222
                $str .= $token . (string) $elem . $secondToken;
223
            }
224
        } else {
225
            $this->rewind();
0 ignored issues
show
Bug introduced by
It seems like rewind() 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

225
            $this->/** @scrutinizer ignore-call */ 
226
                   rewind();
Loading history...
226
            while ($this->valid()) {
0 ignored issues
show
Bug introduced by
It seems like valid() 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

226
            while ($this->/** @scrutinizer ignore-call */ valid()) {
Loading history...
227
                $str .= (string) $this->current();
0 ignored issues
show
Bug introduced by
It seems like current() 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

227
                $str .= (string) $this->/** @scrutinizer ignore-call */ current();
Loading history...
228
                $this->next();
0 ignored issues
show
Bug introduced by
It seems like next() 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

228
                $this->/** @scrutinizer ignore-call */ 
229
                       next();
Loading history...
229
                if ($this->valid()) {
230
                    $str .= $token;
231
                }
232
            }
233
        }
234
235
        return $str;
236
    }
237
238
    /**
239
     * @inheritDoc
240
     */
241
    public function slice(int $begin = 0, int $end = null): SequenceableInterface
242
    {
243
        $it = new SliceIterator($this, $begin, $end);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Iterator expected by parameter $iterator of Mbh\Iterator\SliceIterator::__construct(). ( Ignorable by Annotation )

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

243
        $it = new SliceIterator(/** @scrutinizer ignore-type */ $this, $begin, $end);
Loading history...
244
        return new static($it);
0 ignored issues
show
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with $it. ( Ignorable by Annotation )

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

244
        return /** @scrutinizer ignore-call */ new static($it);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug Best Practice introduced by
The expression return new static($it) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
245
    }
246
247
    /**
248
     * @inheritDoc
249
     */
250
    public function concat(): SequenceableInterface
251
    {
252
        $args = func_get_args();
253
        array_unshift($args, $this);
254
255
        // Concat this iterator, and variadic args
256
        $class = new ReflectionClass('Mbh\Iterator\ConcatIterator');
257
        $concatIt = $class->newInstanceArgs($args);
258
259
        // Create as new immutable's iterator
260
        return new static($concatIt);
0 ignored issues
show
Unused Code introduced by
The call to Mbh\Collection\Traits\Sequenceable::__construct() has too many arguments starting with $concatIt. ( Ignorable by Annotation )

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

260
        return /** @scrutinizer ignore-call */ new static($concatIt);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
Bug Best Practice introduced by
The expression return new static($concatIt) returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
261
    }
262
263
    /**
264
     * @inheritDoc
265
     */
266
    public function find(callable $callback)
267
    {
268
        foreach ($this as $i => $elem) {
269
            if ($callback($elem, $i, $this)) {
270
                return $elem;
271
            }
272
        }
273
    }
274
275
    /**
276
     * @inheritDoc
277
     */
278
    public function sort(callable $callback = null): SequenceableInterface
279
    {
280
        if ($callback) {
281
            return $this->mergeSort($callback);
282
        }
283
284
        return $this->arraySort();
285
    }
286
287
    /**
288
     * @inheritDoc
289
     */
290
    public function sorted(callable $callback = null): SequenceableInterface
291
    {
292
        $copy = FixedArray::fromItems($this);
0 ignored issues
show
Bug introduced by
$this of type Mbh\Collection\Traits\Sequenceable is incompatible with the type Traversable expected by parameter $array of Mbh\Collection\FixedArray::fromItems(). ( Ignorable by Annotation )

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

292
        $copy = FixedArray::fromItems(/** @scrutinizer ignore-type */ $this);
Loading history...
293
294
        if ($callback) {
295
            $copy->mergeSort($callback);
296
        }
297
298
        $copy->arraySort();
299
300
        return static::fromItems($copy);
301
    }
302
303
    /**
304
     * @inheritDoc
305
     */
306
    public function heapSorted(SplHeap $heap): SequenceableInterface
307
    {
308
        return $this->copy()->heapSort($heap);
309
    }
310
311
    /**
312
     * @inheritDoc
313
     */
314
    public function heapSort(SplHeap $heap): SequenceableInterface
315
    {
316
        foreach ($this as $item) {
317
            $heap->insert($item);
318
        }
319
320
        $this->setTraversable(static::fromItems($heap));
321
322
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Mbh\Collection\Traits\Sequenceable which is incompatible with the type-hinted return Mbh\Collection\Interfaces\Sequenceable.
Loading history...
323
    }
324
325
    abstract protected function setTraversable(Traversable $traversable);
326
}
327