Completed
Branch master (35ad35)
by Tristan
17:10 queued 07:53
created

Each::shallow()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Enzyme\Loopy;
4
5
use ArrayAccess;
6
use Closure;
7
use Enzyme\Loopy\Filters\FilterInterface;
8
9
class Each implements LooperInterface
10
{
11
    /**
12
     * If this loop will go deep into the enumerated object.
13
     *
14
     * @var boolean
15
     */
16
    protected $deep;
17
18
    /**
19
     * Stores the current cycle value.
20
     *
21
     * @var integer
22
     */
23
    protected $cycle;
24
25
    /**
26
     * Stored the current index value.
27
     *
28
     * @var integer
29
     */
30
    protected $index;
31
32
    /**
33
     * Stored the current depth value.
34
     *
35
     * @var integer
36
     */
37
    protected $depth;
38
39
    /**
40
     * The optional filter to pass the key and value through
41
     * upon each iteration.
42
     *
43
     * @var FilterInterface
44
     */
45
    protected $filter;
46
47
    /**
48
     * Creates a new Each loop.
49
     *
50
     * @param bool $deep Whether to traverse deeply.
51
     *
52
     * @param FilterInterface|null $filter The optional filter to apply to each iteration.
53
     */
54
    private function __construct($deep, FilterInterface $filter = null)
55
    {
56
        $this->deep = $deep;
57
        $this->filter = $filter;
58
    }
59
60
    /**
61
     * Creates a new shallow Each loopy.
62
     *
63
     * @param FilterInterface|null $filter The optional filter to apply to each iteration.
64
     *
65
     * @return Each
66
     */
67
    public static function shallow(FilterInterface $filter = null)
68
    {
69
        $deep = false;
70
71
        return new static($deep, $filter);
72
    }
73
74
    /**
75
     * Creates a new deep Each loopy.
76
     *
77
     * @param FilterInterface|null $filter The optional filter to apply to each iteration.
78
     *
79
     * @return Each
80
     */
81
    public static function deep(FilterInterface $filter = null)
82
    {
83
        $deep = true;
84
85
        return new static($deep, $filter);
86
    }
87
88
    /**
89
     * {@inheritdoc}
90
     */
91
    public function begin($enumerable, Closure $function, $cycles = 1)
92
    {
93
        if($this->isEnumerable($enumerable) === false) {
94
            throw new InvalidLoopException('The supplied $enumerable object cannot be enumerated.');
95
        }
96
97
        $this->index = 0;
98
        $this->depth = 0;
99
        $this->cycle = 0;
100
101
        for ($i = 0; $i < $cycles; $i++) {
102
            $this->doSingleForeachCycle($enumerable, $function);
103
            $this->cycle++;
104
        }
105
    }
106
107
    /**
108
     * Performs a single foreach cycle.
109
     *
110
     * @param mixed   $enumerable The object to iterate over.
111
     * @param Closure $function   The callback function.
112
     *
113
     * @return void
114
     */
115
    protected function doSingleForeachCycle($enumerable, Closure $function)
116
    {
117
        foreach ($enumerable as $key => $value) {
118
            if ($this->canGoDeeperInto($value)) {
119
                $this->doSingleForeachCycle($value, $function);
120
            } elseif ($this->passesThroughFilter($key, $value)) {
121
                $this->processIteration($key, $value, $function);
122
            }
123
        }
124
    }
125
126
    /**
127
     * Checks if the given key and value pass through the filter,
128
     * if one exists.
129
     *
130
     * @param mixed $key   The key.
131
     * @param mixed $value The value.
132
     *
133
     * @return boolean
134
     */
135
    protected function passesThroughFilter($key, $value)
136
    {
137
        if ($this->filter === null) {
138
            return true;
139
        }
140
141
        return $this->filter->passes($key, $value);
142
    }
143
144
    /**
145
     * Checks whether we can go deeper into this value,
146
     * if the deep setting is set to true.
147
     *
148
     * @param mixed $value The value to check.
149
     *
150
     * @return boolean
151
     */
152
    protected function canGoDeeperInto($value)
153
    {
154
        return $this->deep === true && $this->isEnumerable($value);
155
    }
156
157
    /**
158
     * Checks whether the given item is enumerable.
159
     *
160
     * @param mixed $item The item.
161
     *
162
     * @return boolean
163
     */
164
    protected function isEnumerable($item)
165
    {
166
        return is_array($item) === true || ($item instanceof ArrayAccess) === true;
167
    }
168
169
    /**
170
     * Processes this iterations key and value.
171
     *
172
     * @param mixed   $key      The key.
173
     * @param mixed   $value    The value.
174
     * @param Closure $function The callback function
175
     *
176
     * @return void
177
     */
178
    protected function processIteration($key, $value, $function)
179
    {
180
        $function($this->packBag($key, $value, $function));
0 ignored issues
show
Unused Code introduced by
The call to Each::packBag() has too many arguments starting with $function.

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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
181
        $this->index++;
182
    }
183
184
    /**
185
     * Packs and returns a new bag with the given values.
186
     *
187
     * @param mixed $key   The key.
188
     * @param mixed $value The value.
189
     *
190
     * @return Bag
191
     */
192
    protected function packBag($key, $value)
193
    {
194
        $index = $this->index;
195
        $cycle = $this->cycle;
196
        $depth = $this->depth;
197
198
        return new Bag(compact('key', 'value', 'index', 'cycle', 'depth'));
199
    }
200
}