Passed
Push — 1.x ( bace11...65e39f )
by Ulises Jeremias
02:35
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\CallbackHeap;
6
use Mbh\Iterator\SliceIterator;
7
use Mbh\Iterator\ConcatIterator;
8
use SplFixedArray;
9
use SplHeap;
10
use SplStack;
11
use LimitIterator;
12
use Iterator;
13
use ArrayAccess;
14
use Countable;
15
use CallbackFilterIterator;
16
use JsonSerializable;
17
use RuntimeException;
18
use Traversable;
19
use ReflectionClass;
20
21
/**
22
 * MBHFramework
23
 *
24
 * @link      https://github.com/MBHFramework/mbh-framework
25
 * @copyright Copyright (c) 2017 Ulises Jeremias Cornejo Fandos
26
 * @license   https://github.com/MBHFramework/mbh-framework/blob/master/LICENSE (MIT License)
27
 */
28
29
trait Sequenceable
30
{
31
    use Collection;
32
    use Sort {
33
        Sort::heapSort as heapSortWithCallback;
34
    }
35
36
    /**
37
     * Factory for building FixedArrays from any traversable
38
     *
39
     * @return SequenceableInterface
40
     */
41
    public static function fromItems(Traversable $array): SequenceableInterface
42
    {
43
        // We can only do it this way if we can count it
44
        if ($array instanceof Countable) {
45
            $sfa = new SplFixedArray(count($array));
46
47
            foreach ($array as $i => $elem) {
48
                $sfa[$i] = $elem;
49
            }
50
51
            return new static($sfa);
0 ignored issues
show
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

51
            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...
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...
52
        }
53
54
        // If we can't count it, it's simplest to iterate into an array first
55
        return static::fromArray(iterator_to_array($array));
56
    }
57
58
    /**
59
     * Build from an array
60
     *
61
     * @return SequenceableInterface
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
     * Creates a shallow copy of the collection.
70
     *
71
     * @return CollectionInterface a shallow copy of the collection.
72
     */
73
    public function copy(): CollectionInterface
74
    {
75
        return static::fromArray($this->toArray());
76
    }
77
78
    /**
79
     * Map elements to a new Sequenceable via a callback
80
     *
81
     * @param callable $callback Function to map new data
82
     * @return SequenceableInterface
83
     */
84
    public function map(callable $callback): SequenceableInterface
85
    {
86
        $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

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

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

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

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

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

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

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

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

190
        $it = new SliceIterator(/** @scrutinizer ignore-type */ $this, $begin, $end);
Loading history...
191
        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

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

210
        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...
211
    }
212
213
    /**
214
     * Find a single element
215
     *
216
     * @param callable $callback The test to run on each element
217
     * @return mixed The element we found
218
     */
219
    public function find(callable $callback)
220
    {
221
        foreach ($this as $i => $elem) {
222
            if ($callback($elem, $i, $this)) {
223
                return $elem;
224
            }
225
        }
226
    }
227
228
    /**
229
     * Sorts the collection
230
     *
231
     * @param callable $callback The sort callback
232
     * @return SequenceableInterface
233
     */
234
    public function sort(callable $callback = null): SequenceableInterface
235
    {
236
        if ($callback) {
237
            $this->mergeSort($callback);
238
        }
239
240
        $this->arraySort();
241
242
        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...
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
        if ($callback) {
254
            return $this->mergeSort($callback);
255
        }
256
257
        return $this->arraySort();
258
    }
259
260
    /**
261
     * Sort a new Sequenceable by filtering through a heap.
262
     * Tends to run much faster than array or merge sorts, since you're only
263
     * sorting the pointers, and the sort function is running in a highly
264
     * optimized space.
265
     *
266
     * @param SplHeap $heap The heap to run for sorting
267
     * @return SequenceableInterface
268
     */
269
    public function heapSort(SplHeap $heap): SequenceableInterface
270
    {
271
        foreach ($this as $item) {
272
            $heap->insert($item);
273
        }
274
        return static::fromItems($heap);
275
    }
276
}
277