Passed
Push — 1.x ( 5b3b89...65c981 )
by Ulises Jeremias
02:37
created

Sequenceable::copy()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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
22
/**
23
 * MBHFramework
24
 *
25
 * @link      https://github.com/MBHFramework/mbh-framework
26
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
27
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
28
 */
29
30
trait Sequenceable
31
{
32
    use Collection;
33
    use Sort {
34
        Sort::heapSort as heapSortWithCallback;
35
        Sort::heapSorted as heapSortedWithCallback;
36
    }
37
38
    /**
39
     * Factory for building FixedArrays from any traversable
40
     *
41
     * @return SequenceableInterface
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
     * Build from an array
62
     *
63
     * @return SequenceableInterface
64
     */
65
    public static function fromArray(array $array): SequenceableInterface
66
    {
67
        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

67
        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...
68
    }
69
70
    /**
71
     * Creates a shallow copy of the collection.
72
     *
73
     * @return CollectionInterface a shallow copy of the collection.
74
     */
75
    public function copy(): CollectionInterface
76
    {
77
        return static::fromArray($this->toArray());
78
    }
79
80
    /**
81
     * Map elements to a new Sequenceable via a callback
82
     *
83
     * @param callable $callback Function to map new data
84
     * @return SequenceableInterface
85
     */
86
    public function map(callable $callback): SequenceableInterface
87
    {
88
        $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

88
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
89
        $sfa = new SplFixedArray($count);
90
91
        for ($i = 0; $i < $count; $i++) {
92
            $sfa[$i] = $callback($this[$i], $i, $this);
93
        }
94
95
        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

95
        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...
96
    }
97
98
    /**
99
     * forEach, or "walk" the data
100
     * Exists primarily to provide a consistent interface, though it's seldom
101
     * any better than a simple php foreach. Mainly useful for chaining.
102
     * Named walk for historic reasons - forEach is reserved in PHP
103
     *
104
     * @param callable $callback Function to call on each element
105
     * @return SequenceableInterface
106
     */
107
    public function walk(callable $callback): SequenceableInterface
108
    {
109
        foreach ($this as $i => $elem) {
110
            $callback($elem, $i, $this);
111
        }
112
113
        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...
114
    }
115
116
    /**
117
     * Filter out elements
118
     *
119
     * @param callable $callback Function to filter out on false
120
     * @return SequenceableInterface
121
     */
122
    public function filter(callable $callback): SequenceableInterface
123
    {
124
        $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

124
        $count = count(/** @scrutinizer ignore-type */ $this);
Loading history...
125
        $sfa = new SplFixedArray($count);
126
        $newCount = 0;
127
128
        foreach ($this as $elem) {
129
            if ($callback($elem)) {
130
                $sfa[$newCount++] = $elem;
131
            }
132
        }
133
134
        $sfa->setSize($newCount);
135
        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

135
        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...
136
    }
137
138
    /**
139
     * Reduce to a single value
140
     *
141
     * @param callable $callback Callback(
142
     *     mixed $previous, mixed $current[, mixed $index, mixed $immArray]
143
     * ):mixed Callback to run reducing function
144
     * @param mixed $accumulator Initial value for first argument
145
     */
146
    public function reduce(callable $callback, $accumulator = null)
147
    {
148
        foreach ($this as $i => $elem) {
149
            $accumulator = $callback($accumulator, $elem, $i, $this);
150
        }
151
152
        return $accumulator;
153
    }
154
155
    /**
156
     * Join a set of strings together.
157
     *
158
     * @param string $token Main token to put between elements
159
     * @param string $secondToken If set, $token on left $secondToken on right
160
     * @return string
161
     */
162
    public function join(string $token = ',', string $secondToken = null): string
163
    {
164
        $str = "";
165
        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...
166
            foreach ($this as $i => $elem) {
167
                $str .= $token . (string) $elem . $secondToken;
168
            }
169
        } else {
170
            $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

170
            $this->/** @scrutinizer ignore-call */ 
171
                   rewind();
Loading history...
171
            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

171
            while ($this->/** @scrutinizer ignore-call */ valid()) {
Loading history...
172
                $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

172
                $str .= (string) $this->/** @scrutinizer ignore-call */ current();
Loading history...
173
                $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

173
                $this->/** @scrutinizer ignore-call */ 
174
                       next();
Loading history...
174
                if ($this->valid()) {
175
                    $str .= $token;
176
                }
177
            }
178
        }
179
180
        return $str;
181
    }
182
183
    /**
184
     * Take a slice of the array
185
     *
186
     * @param int $begin Start index of slice
187
     * @param int $end End index of slice
188
     * @return SequenceableInterface
189
     */
190
    public function slice(int $begin = 0, int $end = null): SequenceableInterface
191
    {
192
        $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

192
        $it = new SliceIterator(/** @scrutinizer ignore-type */ $this, $begin, $end);
Loading history...
193
        return new static($it);
0 ignored issues
show
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...
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

193
        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...
194
    }
195
196
    /**
197
     * Concat to the end of this array
198
     *
199
     * @param Traversable,...
200
     * @return SequenceableInterface
201
     */
202
    public function concat(): SequenceableInterface
203
    {
204
        $args = func_get_args();
205
        array_unshift($args, $this);
206
207
        // Concat this iterator, and variadic args
208
        $class = new ReflectionClass('Mbh\Iterator\ConcatIterator');
209
        $concatIt = $class->newInstanceArgs($args);
210
211
        // Create as new immutable's iterator
212
        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

212
        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...
213
    }
214
215
    /**
216
     * Find a single element
217
     *
218
     * @param callable $callback The test to run on each element
219
     * @return mixed The element we found
220
     */
221
    public function find(callable $callback)
222
    {
223
        foreach ($this as $i => $elem) {
224
            if ($callback($elem, $i, $this)) {
225
                return $elem;
226
            }
227
        }
228
    }
229
230
    /**
231
     * Sorts the collection
232
     *
233
     * @param callable $callback The sort callback
234
     * @return SequenceableInterface
235
     */
236
    public function sort(callable $callback = null): SequenceableInterface
237
    {
238
        if ($callback) {
239
            return $this->mergeSort($callback);
240
        }
241
242
        return $this->arraySort();
243
    }
244
245
    /**
246
     * Return a new sorted Sequenceable
247
     *
248
     * @param callable $callback The sort callback
249
     * @return SequenceableInterface
250
     */
251
    public function sorted(callable $callback = null): SequenceableInterface
252
    {
253
        $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

253
        $copy = FixedArray::fromItems(/** @scrutinizer ignore-type */ $this);
Loading history...
254
255
        if ($callback) {
256
            $copy->mergeSort($callback);
257
        }
258
259
        $copy->arraySort();
260
261
        return static::fromItems($copy);
262
    }
263
264
    /**
265
     * Sort a new Sequenceable by filtering through a heap.
266
     * Tends to run much faster than array or merge sorts, since you're only
267
     * sorting the pointers, and the sort function is running in a highly
268
     * optimized space.
269
     *
270
     * @param SplHeap $heap The heap to run for sorting
271
     * @return SequenceableInterface
272
     */
273
    public function heapSorted(SplHeap $heap): SequenceableInterface
274
    {
275
        foreach ($this as $item) {
276
            $heap->insert($item);
277
        }
278
        return static::fromItems($heap);
279
    }
280
281
    /**
282
     * Sort by applying a CallbackHeap and building a new heap
283
     * Can be efficient for sorting large stored objects.
284
     *
285
     * @param callable $callback The comparison callback
286
     * @return SequenceableInterface
287
     */
288
    public function heapSort(SplHeap $heap): SequenceableInterface
289
    {
290
        $this->setTraversable($this->heapSorted($heap));
291
292
        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...
293
    }
294
}
295