functions.php ➔ _last()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Cypress\Curry;
4
5
use Cypress\Curry\Placeholder;
6
7
/**
8
 * @param callable $callable
9
 * @return callable
10
 */
11
function curry($callable)
12
{
13 9
    if (_number_of_required_params($callable) === 0) {
14 9
        return _make_function($callable);
15 7
    }
16
    if (_number_of_required_params($callable) === 1) {
17
        return _curry_array_args($callable, _rest(func_get_args()));
18
    }
19
20
    return _curry_array_args($callable, _rest(func_get_args()));
21
}
22
23
/**
24
 * @param $callable
25
 * @param array $args pass the arguments to be curried as an array
26 2
 *
27
 * @return callable
28
 */
29
function curry_args($callable, array $args)
30
{
31
    return _curry_array_args($callable, $args);
32
}
33
34
/**
35 4
 * @param callable $callable
36 4
 * @return callable
37 4
 */
38
function curry_right($callable)
39
{
40
    if (_number_of_required_params($callable) < 2)
41
        return _make_function($callable);
42
    return _curry_array_args($callable, _rest(func_get_args()), false);
43
}
44
45
/**
46
 * @param callable $callable
47
 * @param array $args pass the arguments to be curried as an array
48 3
 *
49
 * @return callable
50
 */
51
function curry_right_args($callable, array $args)
52
{
53
    return _curry_array_args($callable, $args, false);
54
}
55
56
/**
57
 * @param callable $callable
58
 * @param $args
59
 * @param bool $left
60 15
 * @return callable
61 4
 */
62
function _curry_array_args($callable, $args, $left = true)
63 11
{
64 11
    return function () use ($callable, $args, $left) {
65 11
        if (_is_fullfilled($callable, $args)) {
66
            return _execute($callable, $args, $left);
67 6
        }
68 15
        $newArgs = array_merge($args, func_get_args());
69
        if (_is_fullfilled($callable, $newArgs)) {
70
            return _execute($callable, $newArgs, $left);
71
        }
72
        return _curry_array_args($callable, $newArgs, $left);
73
    };
74
}
75
76
/**
77
 * @internal
78
 * @param $callable
79
 * @param $args
80 15
 * @param $left
81 7
 * @return mixed
82 7
 */
83
function _execute($callable, $args, $left)
84 15
{
85 15
    if (! $left) {
86 1
        $args = array_reverse($args);
87 1
    }
88
89
    $placeholders = _placeholder_positions($args);
90
    if (0 < count($placeholders)) {
91
        $n = _number_of_required_params($callable);
92
        if ($n <= _last($placeholders[count($placeholders) - 1])) {
93 1
            // This means that we have more placeholders then needed
94 1
            // I know that throwing exceptions is not really the 
95 1
            // functional way, but this case should not happen.
96 1
            throw new \Exception("Argument Placeholder found on unexpected position !");
97 1
        }
98
        foreach ($placeholders as $i) {
99 15
            $args[$i] = $args[$n];
100
            array_splice($args, $n, 1);
101
        }
102
    }
103
104
    return call_user_func_array($callable, $args);
105
}
106
107
/**
108
 * @internal
109 11
 * @param array $args
110
 * @return array
111
 */
112
function _rest(array $args)
113
{
114
    return array_slice($args, 1);
115
}
116
117
/**
118
 * @internal
119
 * @param callable $callable
120
 * @param $args
121 20
 * @return bool
122 22
 */
123 22
function _is_fullfilled($callable, $args)
124
{
125
    $args = array_filter($args, function($arg) {
126
        return ! _is_placeholder($arg);
127
    });
128
    return count($args) >= _number_of_required_params($callable);
129
}
130
131
/**
132
 * @internal
133 24
 * @param $callable
134 16
 * @return int
135 16
 */
136 16
function _number_of_required_params($callable)
137
{
138 8
    if (is_array($callable)) {
139 8
        $refl = new \ReflectionClass($callable[0]);
140
        $method = $refl->getMethod($callable[1]);
141
        return $method->getNumberOfRequiredParameters();
142
    }
143
    $refl = new \ReflectionFunction($callable);
144
    return $refl->getNumberOfRequiredParameters();
145
}
146
147
/**
148
 * if the callback is an array(instance, method), 
149
 * it returns an equivalent function for PHP 5.3 compatibility.
150
 *
151
 * @internal 
152 3
 * @param  callable $callable
153
 * @return callable
154 1
 */
155 1
function _make_function($callable)
156 2
{
157
    if (is_array($callable))
158
        return function() use($callable) {
159
            return call_user_func_array($callable, func_get_args());
160
        };
161
    return $callable;
162
}
163
164
/**
165
 * Checks if an argument is a placeholder.
166
 *
167
 * @internal
168 20
 * @param  mixed  $arg
169
 * @return boolean
170
 */
171
function _is_placeholder($arg)
172
{
173
    return $arg instanceof Placeholder;
174
}
175
176
/**
177
 * Gets an array of placeholders positions in the given arguments.
178
 *
179
 * @internal
180 15
 * @param  array $args
181
 * @return array
182
 */
183
function _placeholder_positions($args)
184
{
185
    return array_keys(array_filter($args, 'Cypress\\Curry\\_is_placeholder'));
186
}
187
188
/**
189
 * Get the last element in an array.
190
 *
191
 * @internal
192 1
 * @param  array $array
193
 * @return mixed
194
 */
195
function _last($array)
196
{
197
    return $array[count($array) - 1];
198
}
199
200
/**
201
 * Gets a special placeholder value used to specify "gaps" within curried 
202
 * functions, allowing partial application of any combination of arguments, 
203
 * regardless of their positions. Should be used only for required arguments.
204
 * When used, optional arguments must be at the end of the arguments list.
205 1
 *
206
 * @return Cypress\Curry\Placeholder
207
 */
208
function __()
209
{
210
    return Placeholder::get();
211
}
212