1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Cypress\Curry; |
4
|
|
|
|
5
|
|
|
use Cypress\Curry\Placeholder; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* @param callable $_ |
9
|
|
|
* @return callable |
10
|
|
|
*/ |
11
|
|
View Code Duplication |
function curry($_) |
|
|
|
|
12
|
|
|
{ |
13
|
9 |
|
$args = func_get_args(); |
14
|
9 |
|
$count = is_int($_) ? array_shift($args) + max(count($args) - 1, 0) : null; |
15
|
7 |
|
$callable = array_shift($args); |
16
|
|
|
|
17
|
|
|
if ($count === 0 || (!isset($count) && _number_of_required_params($callable) === 0)) { |
18
|
|
|
return _make_function($callable); |
19
|
|
|
} |
20
|
|
|
|
21
|
|
|
return _curry_array_args($callable, $args, $count); |
22
|
|
|
} |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @param callable $callable |
26
|
2 |
|
* @param array $args pass the arguments to be curried as an array |
27
|
|
|
* |
28
|
|
|
* @return callable |
29
|
|
|
*/ |
30
|
|
|
function curry_args($callable, array $args) |
31
|
|
|
{ |
32
|
|
|
return _curry_array_args($callable, $args); |
33
|
|
|
} |
34
|
|
|
|
35
|
4 |
|
/** |
36
|
4 |
|
* @param callable $_ |
37
|
4 |
|
* @return callable |
38
|
|
|
*/ |
39
|
|
View Code Duplication |
function curry_right($_) |
|
|
|
|
40
|
|
|
{ |
41
|
|
|
$args = func_get_args(); |
42
|
|
|
$count = is_int($_) ? array_shift($args) + max(count($args) - 1, 0) : null; |
43
|
|
|
$callable = array_shift($args); |
44
|
|
|
|
45
|
|
|
if ($count === 0 || (!isset($count) && _number_of_required_params($callable) === 0)) { |
46
|
|
|
return _make_function($callable); |
47
|
|
|
} |
48
|
3 |
|
|
49
|
|
|
return _curry_array_args($callable, $args, $count, false); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param callable $callable |
54
|
|
|
* @param array $args pass the arguments to be curried as an array |
55
|
|
|
* |
56
|
|
|
* @return callable |
57
|
|
|
*/ |
58
|
|
|
function curry_right_args($callable, array $args) |
59
|
|
|
{ |
60
|
15 |
|
return _curry_array_args($callable, $args, null,false); |
61
|
4 |
|
} |
62
|
|
|
|
63
|
11 |
|
|
64
|
11 |
|
/** |
65
|
11 |
|
* @param callable $callable |
66
|
|
|
* @param $args |
67
|
6 |
|
* @param bool $left |
68
|
15 |
|
* @param int $count |
69
|
|
|
* @return callable |
70
|
|
|
*/ |
71
|
|
|
function _curry_array_args($callable, $args, $count = null, $left = true) |
72
|
|
|
{ |
73
|
|
|
return function () use ($callable, $args, $left, $count) { |
74
|
|
|
$newArgs = _merge_args($args, func_get_args(), $left); |
75
|
|
|
|
76
|
|
|
if (_is_fullfilled($callable, $newArgs, $count)) { |
77
|
|
|
return _execute($callable, $newArgs, $count, $left); |
78
|
|
|
} |
79
|
|
|
|
80
|
15 |
|
return _curry_array_args($callable, $newArgs, $count, $left); |
81
|
7 |
|
}; |
82
|
7 |
|
} |
83
|
|
|
|
84
|
15 |
|
|
85
|
15 |
|
/** |
86
|
1 |
|
* @internal |
87
|
1 |
|
* @param $callable |
88
|
|
|
* @param $args |
89
|
|
|
* @param $count |
90
|
|
|
* @param $left |
91
|
|
|
* @return mixed |
92
|
|
|
*/ |
93
|
1 |
|
function _execute($callable, $args, $count, $left) |
94
|
1 |
|
{ |
95
|
1 |
|
if (! $left) { |
96
|
1 |
|
$args = array_reverse($args); |
97
|
1 |
|
} |
98
|
|
|
|
99
|
15 |
|
$n = isset($count) ? $count : _number_of_required_params($callable); |
100
|
|
|
|
101
|
|
|
if (count($args) > $n) { |
102
|
|
|
$extra = array_splice($args, $left ? $n : 0, count($args) - $n); |
103
|
|
|
|
104
|
|
|
if (!isset($count)) |
105
|
|
|
$args = array_merge($args, $left ? $extra : array_reverse($extra)); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
return call_user_func_array($callable, $args); |
109
|
11 |
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @internal |
113
|
|
|
* @param array $args |
114
|
|
|
* @return array |
115
|
|
|
*/ |
116
|
|
|
function _rest(array $args) |
117
|
|
|
{ |
118
|
|
|
return array_slice($args, 1); |
119
|
|
|
} |
120
|
|
|
|
121
|
20 |
|
/** |
122
|
22 |
|
* @internal |
123
|
22 |
|
* @param callable $callable |
124
|
|
|
* @param $args |
125
|
|
|
* @return bool |
126
|
|
|
*/ |
127
|
|
|
function _is_fullfilled($callable, $args, $count = null) |
128
|
|
|
{ |
129
|
|
|
if (!isset($count)) { |
130
|
|
|
$count = _number_of_required_params($callable); |
131
|
|
|
} |
132
|
|
|
|
133
|
24 |
|
return count($args) >= $count && |
134
|
16 |
|
!in_array(Placeholder::get(), $args, true); |
135
|
16 |
|
} |
136
|
16 |
|
|
137
|
|
|
/** |
138
|
8 |
|
* @internal |
139
|
8 |
|
* @param $callable |
140
|
|
|
* @return int |
141
|
|
|
*/ |
142
|
|
|
function _number_of_required_params($callable) |
143
|
|
|
{ |
144
|
|
|
if (is_array($callable)) { |
145
|
|
|
$refl = new \ReflectionClass($callable[0]); |
146
|
|
|
$method = $refl->getMethod($callable[1]); |
147
|
|
|
return $method->getNumberOfRequiredParameters(); |
148
|
|
|
} |
149
|
|
|
$refl = new \ReflectionFunction($callable); |
150
|
|
|
return $refl->getNumberOfRequiredParameters(); |
151
|
|
|
} |
152
|
3 |
|
|
153
|
|
|
/** |
154
|
1 |
|
* if the callback is an array(instance, method), |
155
|
1 |
|
* it returns an equivalent function for PHP 5.3 compatibility. |
156
|
2 |
|
* |
157
|
|
|
* @internal |
158
|
|
|
* @param callable $callable |
159
|
|
|
* @return callable |
160
|
|
|
*/ |
161
|
|
|
function _make_function($callable) |
162
|
|
|
{ |
163
|
|
|
if (is_array($callable)) |
164
|
|
|
return function() use($callable) { |
165
|
|
|
return call_user_func_array($callable, func_get_args()); |
166
|
|
|
}; |
167
|
|
|
return $callable; |
168
|
20 |
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Checks if an argument is a placeholder. |
172
|
|
|
* |
173
|
|
|
* @internal |
174
|
|
|
* @param mixed $arg |
175
|
|
|
* @return boolean |
176
|
|
|
*/ |
177
|
|
|
function _is_placeholder($arg) |
178
|
|
|
{ |
179
|
|
|
return $arg instanceof Placeholder; |
180
|
15 |
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Merge arguments, replacing placeholders |
184
|
|
|
*/ |
185
|
|
|
function _merge_args($args, $newArgs, $left = true) |
|
|
|
|
186
|
|
|
{ |
187
|
|
|
foreach ($args as &$arg) { |
188
|
|
|
if (!_is_placeholder($arg)) |
189
|
|
|
continue; |
190
|
|
|
|
191
|
|
|
$arg = array_shift($newArgs); |
192
|
1 |
|
if (empty($newArgs)) |
193
|
|
|
break; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return array_merge($args, $newArgs); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Gets a special placeholder value used to specify "gaps" within curried |
201
|
|
|
* functions, allowing partial application of any combination of arguments, |
202
|
|
|
* regardless of their positions. Should be used only for required arguments. |
203
|
|
|
* When used, optional arguments must be at the end of the arguments list. |
204
|
|
|
* |
205
|
1 |
|
* @return Cypress\Curry\Placeholder |
206
|
|
|
*/ |
207
|
|
|
function __() |
208
|
|
|
{ |
209
|
|
|
return Placeholder::get(); |
210
|
|
|
} |
211
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.