This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace Tarsana\Functional; |
||
2 | /** |
||
3 | * This file contains Stream internal functions. |
||
4 | * @file |
||
5 | */ |
||
6 | |||
7 | /** |
||
8 | * Operation :: { |
||
9 | * name: String, |
||
10 | * signatures: [[String]], |
||
11 | * fn: Function |
||
12 | * } |
||
13 | * |
||
14 | * @type |
||
15 | */ |
||
16 | |||
17 | /** |
||
18 | * Transformation :: { |
||
19 | * operations: [Operation], |
||
20 | * args: [Any] |
||
21 | * } |
||
22 | * |
||
23 | * @type |
||
24 | */ |
||
25 | |||
26 | /** |
||
27 | * Stream :: { |
||
28 | * operations: {name1: Operation1, ...}, |
||
29 | * data: Any, |
||
30 | * transformations: [Transformation], |
||
31 | * type: String, |
||
32 | * result: Any, |
||
33 | * resolved: Boolean (The result is computed) |
||
34 | * } |
||
35 | * |
||
36 | * @type |
||
37 | */ |
||
38 | |||
39 | /** |
||
40 | * Returns supported types in signatures. |
||
41 | * |
||
42 | * @signature List |
||
43 | * @return array |
||
44 | */ |
||
45 | function _stream_types() { |
||
46 | return [ |
||
47 | 'Null', |
||
48 | 'Boolean', |
||
49 | 'Number', |
||
50 | 'String', |
||
51 | 'Resource', |
||
52 | 'Function', |
||
53 | 'List', // [1, 2, 'Hi'] |
||
0 ignored issues
–
show
|
|||
54 | 'Array', // ['foo' => 'bar', 'baz'] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
64% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
55 | 'Object', |
||
56 | 'Any' |
||
57 | ]; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * Throws an error. |
||
62 | * |
||
63 | * @signature String -> * |
||
64 | * 'unknown-callable', callable |
||
65 | * 'invalid-signature', string |
||
66 | * 'unknown-operation', string |
||
67 | * 'invalid-args', string, [string], [[string]] |
||
68 | * 'duplicated-operation', string |
||
69 | * @param string $type |
||
70 | * @return void |
||
71 | */ |
||
72 | function _stream_throw_error($type) { |
||
73 | $params = tail(func_get_args()); |
||
74 | $msg = 'Stream: unknown error happened'; |
||
75 | switch ($type) { |
||
76 | case 'unknown-callable': |
||
77 | $fn = is_string($params[0]) ? $params[0] : toString($params[0]); |
||
78 | $msg = "Stream: unknown callable '{$fn}'"; |
||
79 | break; |
||
80 | case 'invalid-signature': |
||
81 | $msg = "Stream: invalid signature '{$params[0]}' it should follow the syntax 'TypeArg1 -> TypeArg2 -> ... -> ReturnType' and types to use are Boolean, Number, String, Resource, Function, List, Array, Object, Any"; |
||
82 | break; |
||
83 | case 'unknown-operation': |
||
84 | $msg = "Stream: call to unknown operation '{$params[0]}'"; |
||
85 | break; |
||
86 | case 'duplicated-operation': |
||
87 | $msg = "Stream: operation '{$params[0]}' already exists"; |
||
88 | break; |
||
89 | case 'ambiguous-signatures': |
||
90 | $msg = "Stream: signatures of the operation '{$params[0]}' are duplicated or ambiguous"; |
||
91 | break; |
||
92 | case 'wrong-operation-args': |
||
93 | $args = join(', ', $params[0]); |
||
94 | $msg = "Stream: wrong arguments ({$args}) given to operation '{$params[1]}'"; |
||
95 | break; |
||
96 | case 'wrong-transformation-args': |
||
97 | $args = join(', ', $params[1]); |
||
98 | $types = join(' or ', map(pipe(join(', '), prepend('('), append(')')), $params[2])); |
||
99 | |||
100 | $msg = "Stream: operation '{$params[0]}' could not be called with arguments types ({$args}); expected types are {$types}"; |
||
101 | break; |
||
102 | } |
||
103 | throw Error::of($msg); |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Creates an operation. |
||
108 | * |
||
109 | * ```php |
||
110 | * // Using function name |
||
111 | * $length = F\_stream_operation('length', 'List|Array -> Number', 'count'); |
||
112 | * $length; //=> ['name' => 'length', 'signatures' => [['List', 'Number'], ['Array', 'Number']], 'fn' => 'count'] |
||
113 | * // Using closure |
||
114 | * $increment = function($x) { |
||
115 | * return 1 + $x; |
||
116 | * }; |
||
117 | * $operation = F\_stream_operation('increment', 'Number -> Number', $increment); |
||
118 | * $operation; //=> ['name' => 'increment', 'signatures' => [['Number', 'Number']], 'fn' => $increment] |
||
119 | * // Without callable |
||
120 | * F\_stream_operation('count', 'List -> Number'); //=> ['name' => 'count', 'signatures' => [['List', 'Number']], 'fn' => 'count'] |
||
121 | * // Invalid signature |
||
122 | * F\_stream_operation('count', 'Number'); // throws "Stream: invalid signature 'Number' it should follow the syntax 'TypeArg1 -> TypeArg2 -> ... -> ReturnType' and types to use are Boolean, Number, String, Resource, Function, List, Array, Object, Any" |
||
123 | * // Invalid callable |
||
124 | * F\_stream_operation('foo', 'List -> Number'); // throws "Stream: unknown callable 'foo'" |
||
125 | * ``` |
||
126 | * |
||
127 | * @signature String -> String -> Maybe(Function) -> Operation |
||
128 | * @param string $name |
||
129 | * @param string $signature |
||
130 | * @param callable $fn |
||
0 ignored issues
–
show
There is no parameter named
$fn . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
131 | * @return array |
||
132 | */ |
||
133 | function _stream_operation($name, $signature, $callable = null) { |
||
134 | $callable = $callable ?: $name; |
||
135 | if (!is_callable($callable)) |
||
136 | _stream_throw_error('unknown-callable', $callable); |
||
137 | |||
138 | return [ |
||
139 | 'name' => $name, |
||
140 | 'signatures' => _stream_make_signatures($signature), |
||
141 | 'fn' => $callable |
||
142 | ]; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Transforms a signature text to an array of signatures. |
||
147 | * |
||
148 | * ```php |
||
149 | * F\_stream_make_signatures('Number|List -> Number -> String|Array -> Number'); //=> [ |
||
150 | * ['Number', 'Number', 'String', 'Number'], |
||
151 | * ['List', 'Number', 'String', 'Number'], |
||
152 | * ['Number', 'Number', 'Array', 'Number'], |
||
153 | * ['List', 'Number', 'Array', 'Number'] |
||
154 | * ] |
||
155 | * F\_stream_make_signatures('List'); // throws "Stream: invalid signature 'List' it should follow the syntax 'TypeArg1 -> TypeArg2 -> ... -> ReturnType' and types to use are Boolean, Number, String, Resource, Function, List, Array, Object, Any" |
||
156 | * F\_stream_make_signatures('List -> Foo'); // throws "Stream: invalid signature 'List -> Foo' it should follow the syntax 'TypeArg1 -> TypeArg2 -> ... -> ReturnType' and types to use are Boolean, Number, String, Resource, Function, List, Array, Object, Any" |
||
157 | * ``` |
||
158 | * |
||
159 | * @signature String -> [[String]] |
||
160 | * @param string $text |
||
161 | * @return array |
||
162 | */ |
||
163 | function _stream_make_signatures($text) { |
||
164 | // Assuming $text = 'Number|List -> Number -> String|Array -> Number' |
||
165 | $parts = map(pipe(split('|'), map(pipe('trim', _stream_ensure_type($text)))), split('->', $text)); |
||
166 | // $parts = [['Number', 'List'], ['Number'], ['String', 'Array'], ['Number']] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
71% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
167 | if (length($parts) < 2) |
||
168 | _stream_throw_error('invalid-signature', $text); |
||
169 | |||
170 | return reduce(function($result, $part){ |
||
171 | return chain(function($item) use($result){ |
||
172 | return map(append($item), $result); |
||
173 | }, $part); |
||
174 | }, [[]], $parts); |
||
175 | // 0: $result = [[]] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
59% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
176 | // 1: $part = ['Number', 'List'] => $result = [['Number'], ['List']] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
62% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
177 | // 2: $part = ['Number'] => $result = [['Number', 'Number'], ['List', 'Number']] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
62% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
178 | // 2: $part = ['String', 'Array'] => $result = [['Number', 'Number', 'String'], ['List', 'Number', 'String'], |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
63% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
179 | // ['Number', 'Number', 'Array'], ['List', 'Number', 'Array']] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
73% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
180 | // 3: $part = ['Number'] => $result = [['Number', 'Number', 'String', 'Number'], |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
60% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
181 | // ['List', 'Number', 'String', 'Number'], |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
72% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
182 | // ['Number', 'Number', 'Array', 'Number'], |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
72% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
183 | // ['List', 'Number', 'Array', 'Number']] |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
72% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Ensures an element of a signature is a correct type or throws an error if not. |
||
188 | * |
||
189 | * ```php |
||
190 | * F\_stream_ensure_type('List -> Bar', 'List'); //=> 'List' |
||
191 | * F\_stream_ensure_type('List -> Bar', 'Bar'); // throws "Stream: invalid signature 'List -> Bar' it should follow the syntax 'TypeArg1 -> TypeArg2 -> ... -> ReturnType' and types to use are Boolean, Number, String, Resource, Function, List, Array, Object, Any" |
||
192 | * ``` |
||
193 | * @signature String -> String -> String |
||
194 | * @param string $signature |
||
0 ignored issues
–
show
There is no parameter named
$signature . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
195 | * @param string $type |
||
0 ignored issues
–
show
There is no parameter named
$type . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
196 | * @return string |
||
197 | */ |
||
198 | function _stream_ensure_type() { |
||
199 | $ensureType = function($signature, $type) { |
||
200 | if (! contains($type, _stream_types())) |
||
201 | _stream_throw_error('invalid-signature', $signature); |
||
202 | return $type; |
||
203 | }; |
||
204 | return apply(curry($ensureType), func_get_args()); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Makes a Stream with the given args. |
||
209 | * |
||
210 | * @signature [Operation] -> Any -> [Transformation] -> String -> Any -> Boolean -> Stream |
||
211 | * @param array $operations |
||
212 | * @param mixed $data |
||
213 | * @param array $transformations |
||
214 | * @param string $type |
||
215 | * @param mixed $result |
||
216 | * @param bool $resolved |
||
217 | * @return array |
||
218 | */ |
||
219 | function _stream_make($operations, $data, $transformations, $type, $result, $resolved) { |
||
220 | return [ |
||
221 | 'data' => $data, |
||
222 | 'type' => $type, |
||
223 | 'result' => $result, |
||
224 | 'resolved' => $resolved, |
||
225 | 'operations' => $operations, |
||
226 | 'transformations' => $transformations |
||
227 | ]; |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Creates a Stream with operations and initial data. |
||
232 | * |
||
233 | * ```php |
||
234 | * $map = F\map(); |
||
235 | * $operations = [ |
||
236 | * F\_stream_operation('length', 'List|Array -> Number', 'count'), |
||
237 | * F\_stream_operation('length', 'String -> Number', 'strlen'), |
||
238 | * F\_stream_operation('map', 'Function -> List -> List', $map) |
||
239 | * ]; |
||
240 | * |
||
241 | * F\_stream($operations, 11); //=> [ |
||
242 | * 'data' => 11, |
||
243 | * 'type' => 'Number', |
||
244 | * 'result' => 11, |
||
245 | * 'resolved' => true, |
||
246 | * 'operations' => [ |
||
247 | * 'length' => [ |
||
248 | * [ |
||
249 | * 'name' => 'length', |
||
250 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
251 | * 'fn' => 'count' |
||
252 | * ], |
||
253 | * [ |
||
254 | * 'name' => 'length', |
||
255 | * 'signatures' => [['String', 'Number']], |
||
256 | * 'fn' => 'strlen' |
||
257 | * ] |
||
258 | * ], |
||
259 | * 'map' => [ |
||
260 | * [ |
||
261 | * 'name' => 'map', |
||
262 | * 'signatures' => [['Function', 'List', 'List']], |
||
263 | * 'fn' => $map |
||
264 | * ] |
||
265 | * ] |
||
266 | * ], |
||
267 | * 'transformations' => [] |
||
268 | * ] |
||
269 | * ``` |
||
270 | * |
||
271 | * @param array $operations |
||
272 | * @param mixed $data |
||
273 | * @return array |
||
274 | */ |
||
275 | function _stream($operations, $data) { |
||
276 | return _stream_make( |
||
277 | map(_f('_stream_validate_operations'), groupBy(get('name'), $operations)), |
||
278 | $data, |
||
279 | [], |
||
280 | type($data), |
||
281 | $data, |
||
282 | true |
||
283 | ); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Validates a list of operations having the same name. |
||
288 | * It throws an error if a signature is duplicated. |
||
289 | * ```php |
||
290 | * F\_stream_validate_operations([ |
||
291 | * [ |
||
292 | * 'name' => 'length', |
||
293 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
294 | * 'fn' => 'count' |
||
295 | * ], |
||
296 | * [ |
||
297 | * 'name' => 'length', |
||
298 | * 'signatures' => [['String', 'Number']], |
||
299 | * 'fn' => 'strlen' |
||
300 | * ] |
||
301 | * ]); //=> [ |
||
302 | * [ |
||
303 | * 'name' => 'length', |
||
304 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
305 | * 'fn' => 'count' |
||
306 | * ], |
||
307 | * [ |
||
308 | * 'name' => 'length', |
||
309 | * 'signatures' => [['String', 'Number']], |
||
310 | * 'fn' => 'strlen' |
||
311 | * ] |
||
312 | * ] |
||
313 | * |
||
314 | * F\_stream_validate_operations([ |
||
315 | * [ |
||
316 | * 'name' => 'length', |
||
317 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
318 | * 'fn' => 'count' |
||
319 | * ], |
||
320 | * [ |
||
321 | * 'name' => 'length', |
||
322 | * 'signatures' => [['String', 'Number'], ['List', 'Number']], |
||
323 | * 'fn' => 'strlen' |
||
324 | * ] |
||
325 | * ]); // throws "Stream: signatures of the operation 'length' are duplicated or ambiguous" |
||
326 | * ``` |
||
327 | * |
||
328 | * @param array $operations |
||
329 | * @return array |
||
330 | */ |
||
331 | function _stream_validate_operations($operations) { |
||
332 | $signatures = chain(get('signatures'), $operations); |
||
333 | if (length($signatures) != length(uniqueBy(equalBy(map(init())), $signatures))) { |
||
334 | _stream_throw_error('ambiguous-signatures', get('name', head($operations))); |
||
335 | } |
||
336 | return $operations; |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Applies an operation (adds a transformation) to a stream. |
||
341 | * ```php |
||
342 | * $operations = [ |
||
343 | * F\_stream_operation('length', 'List|Array -> Number', 'count'), |
||
344 | * F\_stream_operation('length', 'String -> Number', 'strlen'), |
||
345 | * F\_stream_operation('map', 'Function -> List -> List', F\map()) |
||
346 | * ]; |
||
347 | * |
||
348 | * $stream = F\_stream($operations, [1, 2, 3]); |
||
349 | * |
||
350 | * F\_stream_apply_operation('length', [], $stream); //=> [ |
||
351 | * 'data' => [1, 2, 3], |
||
352 | * 'type' => 'Number', |
||
353 | * 'result' => null, |
||
354 | * 'resolved' => false, |
||
355 | * 'operations' => [ |
||
356 | * 'length' => [ |
||
357 | * [ |
||
358 | * 'name' => 'length', |
||
359 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
360 | * 'fn' => 'count' |
||
361 | * ], |
||
362 | * [ |
||
363 | * 'name' => 'length', |
||
364 | * 'signatures' => [['String', 'Number']], |
||
365 | * 'fn' => 'strlen' |
||
366 | * ] |
||
367 | * ], |
||
368 | * 'map' => [ |
||
369 | * [ |
||
370 | * 'name' => 'map', |
||
371 | * 'signatures' => [['Function', 'List', 'List']], |
||
372 | * 'fn' => F\map() |
||
373 | * ] |
||
374 | * ] |
||
375 | * ], |
||
376 | * 'transformations' => [ |
||
377 | * [ |
||
378 | * 'operations' => [[ |
||
379 | * 'name' => 'length', |
||
380 | * 'signatures' => [['List', 'Number']], |
||
381 | * 'fn' => 'count' |
||
382 | * ]], |
||
383 | * 'args' => [] |
||
384 | * ] |
||
385 | * ] |
||
386 | * ] |
||
387 | * |
||
388 | * F\_stream_apply_operation('foo', [], $stream); // throws "Stream: call to unknown operation 'foo'" |
||
389 | * F\_stream_apply_operation('length', [5], $stream); // throws "Stream: wrong arguments (Number, List) given to operation 'length'" |
||
390 | * F\_stream_apply_operation('map', [], $stream); // throws "Stream: wrong arguments (List) given to operation 'map'" |
||
391 | * F\_stream_apply_operation('map', [[1, 2]], $stream); // throws "Stream: wrong arguments (List, List) given to operation 'map'" |
||
392 | * |
||
393 | * ``` |
||
394 | * |
||
395 | * @signature String -> [Any] -> Stream -> Stream |
||
396 | * @param string $name |
||
397 | * @param array $args |
||
398 | * @param array $stream |
||
399 | * @return array |
||
400 | */ |
||
401 | function _stream_apply_operation($name, $args, $stream) { |
||
402 | $operations = getPath(['operations', $name], $stream); |
||
403 | if (null == $operations) { |
||
404 | _stream_throw_error('unknown-operation', $name); |
||
405 | } |
||
406 | |||
407 | $argsTypes = append(get('type', $stream), map(type(), $args)); |
||
408 | $validOperations = filter(_stream_operation_is_applicable($argsTypes), |
||
409 | chain(_f('_stream_split_operation_signatures'), $operations)); |
||
410 | if (0 == length($validOperations)) { |
||
411 | _stream_throw_error('wrong-operation-args', $argsTypes, $name); |
||
412 | } |
||
413 | |||
414 | $returnTypes = map(_f('_stream_return_type_of_operation'), $validOperations); |
||
415 | $returnType = reduce(_f('_stream_merge_types'), head($returnTypes), $returnTypes); |
||
416 | return _stream_make( |
||
417 | get('operations', $stream), // operations |
||
418 | get('data', $stream), // data |
||
419 | append([ |
||
420 | 'operations' => $validOperations, |
||
421 | 'args' => $args |
||
422 | ], get('transformations', $stream)), // transformations |
||
423 | $returnType, // type |
||
424 | null, // result |
||
425 | false // resolved |
||
426 | ); |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Splits an operation with multiple signatures into a list of operation; each having one signature. |
||
431 | * ```php |
||
432 | * F\_stream_split_operation_signatures([ |
||
433 | * 'name' => 'length', |
||
434 | * 'signatures' => [['List', 'Number'], ['Array', 'Number']], |
||
435 | * 'fn' => 'count' |
||
436 | * ]); //=> [ |
||
437 | * [ |
||
438 | * 'name' => 'length', |
||
439 | * 'signatures' => [['List', 'Number']], |
||
440 | * 'fn' => 'count' |
||
441 | * ], |
||
442 | * [ |
||
443 | * 'name' => 'length', |
||
444 | * 'signatures' => [['Array', 'Number']], |
||
445 | * 'fn' => 'count' |
||
446 | * ] |
||
447 | * ] |
||
448 | * ``` |
||
449 | * |
||
450 | * @signature Operation -> [Operation] |
||
451 | * @param array $operation |
||
452 | * @return array |
||
453 | */ |
||
454 | function _stream_split_operation_signatures($operation) { |
||
455 | $name = get('name', $operation); |
||
456 | $fn = get('fn', $operation); |
||
457 | return map(function($signature) use($name, $fn) { |
||
458 | return [ |
||
459 | 'name' => $name, |
||
460 | 'fn' => $fn, |
||
461 | 'signatures' => [$signature] |
||
462 | ]; |
||
463 | }, get('signatures', $operation)); |
||
464 | } |
||
465 | |||
466 | /** |
||
467 | * Checks if the operation can be applied with the given arguments types. |
||
468 | * |
||
469 | * ```php |
||
470 | * $isApplicable = F\_stream_operation_is_applicable(['Number', 'Number']); |
||
471 | * $isApplicable(F\_stream_operation('add', 'Number -> Number -> Number', F\plus())); //=> true |
||
472 | * $isApplicable(F\_stream_operation('length', 'List|Array|String -> Number', F\length())); //=> false |
||
473 | * F\_stream_operation_is_applicable( |
||
474 | * ['List'], |
||
475 | * F\_stream_operation('length', 'List|Array|String -> Number', F\length()) |
||
476 | * ); //=> true |
||
477 | * F\_stream_operation_is_applicable( |
||
478 | * ['String'], |
||
479 | * F\_stream_operation('length', 'List|Array|String -> Number', F\length()) |
||
480 | * ); //=> true |
||
481 | * F\_stream_operation_is_applicable( |
||
482 | * ['Number'], |
||
483 | * F\_stream_operation('length', 'List|Array|String -> Number', F\length()) |
||
484 | * ); //=> false |
||
485 | * F\_stream_operation_is_applicable( |
||
486 | * ['Number', 'String'], |
||
487 | * F\_stream_operation('fill', 'Number -> Any -> List', function(){}) |
||
488 | * ); //=> true |
||
489 | * F\_stream_operation_is_applicable( |
||
490 | * ['Any', 'String'], |
||
491 | * F\_stream_operation('fill', 'Number -> Any -> List', function(){}) |
||
492 | * ); //=> true |
||
493 | * ``` |
||
494 | * |
||
495 | * @signature [String] -> Operation -> Boolean |
||
496 | * @param array $argsTypes |
||
0 ignored issues
–
show
There is no parameter named
$argsTypes . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
497 | * @param array $operation |
||
0 ignored issues
–
show
There is no parameter named
$operation . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
498 | * @return bool |
||
499 | */ |
||
500 | function _stream_operation_is_applicable() { |
||
501 | static $operationIsApplicable = false; |
||
502 | $operationIsApplicable = $operationIsApplicable ?: curry(function($argsTypes, $operation) { |
||
503 | return null !== findIndex(function($signature) use($argsTypes) { |
||
504 | $types = init($signature); |
||
505 | if (length($types) == length($argsTypes)) { |
||
506 | return allSatisfies(function($pair) { |
||
507 | return 'Any' == $pair[0] || 'Any' == $pair[1] || $pair[0] == $pair[1]; |
||
508 | }, pairsFrom($types, $argsTypes)); |
||
509 | } |
||
510 | return false; |
||
511 | }, get('signatures', $operation)); |
||
512 | }); |
||
513 | return _apply($operationIsApplicable, func_get_args()); |
||
514 | } |
||
515 | |||
516 | /** |
||
517 | * Gets the return type of an operation having a single signature. |
||
518 | * |
||
519 | * ```php |
||
520 | * F\_stream_return_type_of_operation(F\_stream_operation( |
||
521 | * 'count', 'List -> Number' |
||
522 | * )); //=> 'Number' |
||
523 | * F\_stream_return_type_of_operation(F\_stream_operation( |
||
524 | * 'count', 'List ->Function -> String' |
||
525 | * )); //=> 'String' |
||
526 | * F\_stream_return_type_of_operation(F\_stream_operation( |
||
527 | * 'count', 'List ->Function -> Any' |
||
528 | * )); //=> 'Any' |
||
529 | * ``` |
||
530 | * |
||
531 | * @signature Operation -> String |
||
532 | * @param array $operation |
||
533 | * @return string |
||
534 | */ |
||
535 | function _stream_return_type_of_operation($operation) { |
||
536 | return last(getPath(['signatures', 0], $operation)); |
||
537 | } |
||
538 | |||
539 | /** |
||
540 | * Returns `$type1` if types are equal and `Any` if not. |
||
541 | * |
||
542 | * ```php |
||
543 | * F\_stream_merge_types('Number', 'Number'); //=> 'Number' |
||
544 | * F\_stream_merge_types('Number', 'String'); //=> 'Any' |
||
545 | * F\_stream_merge_types('Any', 'String'); //=> 'Any' |
||
546 | * ``` |
||
547 | * |
||
548 | * @signature String -> String -> String |
||
549 | * @param string $type1 |
||
550 | * @param string $type2 |
||
551 | * @return string |
||
552 | */ |
||
553 | function _stream_merge_types($type1, $type2) { |
||
554 | return ($type1 == $type2) |
||
555 | ? $type1 |
||
556 | : 'Any'; |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * Computes the result of a stream. |
||
561 | * |
||
562 | * ```php |
||
563 | * $operations = [ |
||
564 | * F\_stream_operation('length', 'List|Array -> Number', 'count'), |
||
565 | * F\_stream_operation('length', 'String -> Number', 'strlen'), |
||
566 | * F\_stream_operation('map', 'Function -> List -> List', F\map()), |
||
567 | * F\_stream_operation('reduce', 'Function -> Any -> List -> Any', F\reduce()), |
||
568 | * F\_stream_operation('increment', 'Number -> Number', F\plus(1)), |
||
569 | * F\_stream_operation('upperCase', 'String -> String', F\upperCase()), |
||
570 | * F\_stream_operation('toString', 'Any -> String', F\toString()), |
||
571 | * F\_stream_operation('head', 'List -> Any', F\head()) |
||
572 | * ]; |
||
573 | * |
||
574 | * $stream = F\_stream($operations, [1, 2, 3]); |
||
575 | * $stream = F\_stream_apply_operation('length', [], $stream); |
||
576 | * $stream = F\_stream_resolve($stream); |
||
577 | * F\get('resolved', $stream); //=> true |
||
578 | * F\get('result', $stream); //=> 3 |
||
579 | * |
||
580 | * $stream = F\_stream($operations, [1, 2, 3]); |
||
581 | * $stream = F\_stream_apply_operation('map', [F\plus(2)], $stream); // [3, 4, 5] |
||
582 | * $stream = F\_stream_apply_operation('reduce', [F\plus(), 0], $stream); // 12 |
||
583 | * $stream = F\_stream_apply_operation('increment', [], $stream); // 13 |
||
584 | * $stream = F\_stream_resolve($stream); |
||
585 | * F\get('resolved', $stream); //=> true |
||
586 | * F\get('result', $stream); //=> 13 |
||
587 | * |
||
588 | * $stream = F\_stream($operations, []); |
||
589 | * $stream = F\_stream_apply_operation('head', [], $stream); // null |
||
590 | * $stream = F\_stream_apply_operation('increment', [], $stream); // Error |
||
591 | * $stream = F\_stream_apply_operation('toString', [], $stream); // Error |
||
592 | * $stream = F\_stream_resolve( $stream); // throws "Stream: operation 'increment' could not be called with arguments types (Null); expected types are (Number)" |
||
593 | * |
||
594 | * ``` |
||
595 | * |
||
596 | * @signature Stream -> Stream |
||
597 | * @param array $stream |
||
598 | * @return array |
||
599 | */ |
||
600 | function _stream_resolve($stream) { |
||
601 | if (get('resolved', $stream)) |
||
602 | return $stream; |
||
603 | $transformations = get('transformations', $stream); |
||
604 | $transformation = head($transformations); |
||
605 | if (null === $transformation) { |
||
606 | return _stream_make( |
||
607 | get('operations', $stream), // operations |
||
608 | get('data', $stream), // data |
||
609 | get('transformations', $stream), // transformations |
||
610 | get('type', $stream), // type |
||
611 | get('data', $stream), // result |
||
612 | true // resolved |
||
613 | ); |
||
614 | } |
||
615 | |||
616 | $args = append(get('data', $stream), get('args', $transformation)); |
||
617 | $argsTypes = map(type(), $args); |
||
618 | $operations = get('operations', $transformation); |
||
619 | $applicableOperations = filter(_stream_operation_is_applicable($argsTypes), $operations); |
||
620 | if (empty($applicableOperations)) { |
||
621 | $types = map(pipe(get('signatures'), head(), init()), $operations); |
||
622 | _stream_throw_error('wrong-transformation-args', getPath([0, 'name'], $operations), $argsTypes, $types); |
||
623 | } |
||
624 | |||
625 | return _stream_resolve(_stream_make( |
||
626 | get('operations', $stream), // operations |
||
627 | _apply(getPath([0, 'fn'], $applicableOperations), $args), // data |
||
628 | tail($transformations), // transformations |
||
629 | get('type', $stream), // type |
||
630 | null, // result |
||
631 | false // resolved |
||
632 | )); |
||
633 | } |
||
634 | |||
635 | /** |
||
636 | * Applies a function to a single argument. |
||
637 | * To be used as the `then()` method of Stream. |
||
638 | * |
||
639 | * @signature (a -> b) -> a -> b |
||
640 | * @param callable $fn |
||
641 | * @param mixed $arg |
||
642 | * @return mixed |
||
643 | */ |
||
644 | function _stream_then($fn, $arg) { |
||
645 | return _apply($fn, [$arg]); |
||
646 | } |
||
647 | |||
648 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.