isEqualIn()   A
last analyzed

Complexity

Conditions 6
Paths 1

Size

Total Lines 25
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 15
nc 1
nop 1
dl 0
loc 25
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Comparison functions
5
 *
6
 * This file is part of PinkCrab Function Constructors.
7
 *
8
 * PinkCrab Function Constructors is free software: you can redistribute it and/or modify it under the terms of the
9
 * GNU General Public License as published by the Free Software Foundation, either version 2
10
 * of the License, or (at your option) any later version.
11
 *
12
 * PinkCrab Function Constructors is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
13
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 * See the GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with PinkCrab Function Constructors.
17
 * If not, see <https://www.gnu.org/licenses/>.
18
 *
19
 * @author Glynn Quelch <[email protected]>
20
 * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
21
 * @package PinkCrab\FunctionConstructors
22
 * @since 0.0.1
23
 *
24
 * @template Number of int|float
25
 * @phpstan-template Number of int|float
26
 * @psalm-template Number of int|float
27
 */
28
29
declare(strict_types=1);
30
31
namespace PinkCrab\FunctionConstructors\Comparisons;
32
33
use Closure;
34
35
/**
36
 * Returns a callback for checking is a value is equal.
37
 * Works with String, Ints, Floats, Array, Objects & Bool
38
 *
39
 * @param mixed $a The value to compare against.
40
 * @return Closure(mixed $b):bool
41
 */
42
function isEqualTo($a): Closure
43
{
44
    /**
45
     * @param mixed $b The values to compare with
46
     * @return bool
47
     */
48
    return function ($b) use ($a): bool {
49
        if (! sameScalar($b, $a)) {
50
            return false;
51
        }
52
53
        switch (gettype($b)) {
54
            case 'string':
55
            case 'integer':
56
            case 'double':
57
            case 'boolean':
58
                $equal = $a === $b;
59
                break;
60
            case 'object':
61
                $equal = count(get_object_vars($a)) === count(array_intersect_assoc((array) $a, (array) $b));
62
                break;
63
            case 'array':
64
                $equal = count($a) === count(array_intersect_assoc($a, $b));
65
                break;
66
            default:
67
                $equal = false;
68
                break;
69
        }
70
        return $equal;
71
    };
72
}
73
74
/**
75
 * Returns a callable for checking if a value is not the same as the base ($a).
76
 *
77
 * @param mixed $a
78
 * @return Closure(mixed $b):bool
79
 */
80
function isNotEqualTo($a): Closure
81
{
82
    /**
83
     * @param mixed $b The values to compare with
84
     * @return bool
85
     */
86
    return function ($b) use ($a): bool {
87
        return ! isEqualTo($a)($b);
88
    };
89
}
90
91
/**
92
 * Returns a callable for checking the base is larger than comparison.
93
 * If the comparison value is not a int or float, will return false.
94
 *
95
 * @param Number $a
96
 * @return Closure(Number $b):bool
97
 */
98
function isGreaterThan($a): Closure
99
{
100
    /**
101
     * @param Number $b
102
     * @return bool
103
     */
104
    return function ($b) use ($a): bool {
105
        return isEqualIn(array( 'integer', 'double' ))(gettype($b))
106
            ? $a < $b : false;
107
    };
108
}
109
110
/**
111
 * Returns a callable for checking the base is smaller than comparison.
112
 * If the comparison value is not a int or float, will return false.
113
 *
114
 * @param Number $a
115
 * @return Closure(Number $b):bool
116
 */
117
function isLessThan($a): Closure
118
{
119
    /**
120
     * @param mixed $b
121
     * @return bool
122
     */
123
    return function ($b) use ($a): bool {
124
        return isEqualIn(array( 'integer', 'double' ))(gettype($b))
125
            ? $a > $b : false;
126
    };
127
}
128
129
/**
130
 * Returns a closure for checking if the value passes is
131
 * less than or equal to the comparison.
132
 *
133
 * @param Number $a The base value to compare against must be int or float.
134
 * @return Closure(Number): bool
135
 */
136
function isLessThanOrEqualTo($a): Closure
137
{
138
    /**
139
     * @param Number $b The base value to compare with must be int or float.
140
     * @return bool
141
     */
142
    return function ($b) use ($a): bool {
143
        return any(isEqualTo($a), isLessThan($a))($b);
144
    };
145
}
146
147
/**
148
 * Returns a closure for checking if the value passes is
149
 * greater than or equal to the comparison.
150
 *
151
 * @param Number $a
152
 * @return Closure(Number): bool
153
 */
154
function isGreaterThanOrEqualTo($a): Closure
155
{
156
    /**
157
     * @param Number $b
158
     * @return bool
159
     */
160
    return function ($b) use ($a): bool {
161
        return any(isEqualTo($a), isGreaterThan($a))($b);
162
    };
163
}
164
165
/**
166
 * Checks if a value is in an array of values.
167
 *
168
 * @param mixed[] $a
169
 * @return Closure(mixed $b):?bool
170
 */
171
function isEqualIn(array $a): Closure
172
{
173
    /**
174
     * @param mixed[] $b The array of values which it could be
175
     * @return bool
176
     */
177
    return function ($b) use ($a): ?bool {
178
        if (
179
            is_numeric($b) || is_bool($b) ||
180
            is_string($b) || is_array($b)
181
        ) {
182
            return in_array($b, $a, true);
183
        } elseif (is_object($b)) {
184
            return in_array(
185
                (array) $b,
186
                array_map(
187
                    function ($e): array {
188
                        return (array) $e;
189
                    },
190
                    $a
191
                ),
192
                true
193
            );
194
        } else {
195
            return null;
196
        }
197
    };
198
}
199
200
/**
201
 * Simple named function for ! empty()
202
 * Allows to be used in function composition.
203
 *
204
 * @param mixed $value The value
205
 * @return bool
206
 */
207
function notEmpty($value): bool
208
{
209
    return ! empty($value);
210
}
211
212
/**
213
 * Groups callbacks and checks they all return true.
214
 *
215
 * @param callable(mixed):bool ...$callables
216
 * @return Closure(mixed):bool
217
 */
218
function groupAnd(callable ...$callables): Closure
219
{
220
    /**
221
     * @param mixed $value
222
     * @return bool
223
     */
224
    return function ($value) use ($callables): bool {
225
        return (bool) array_reduce(
226
            $callables,
227
            function ($result, $callable) use ($value) {
228
                return (is_bool($result) && $result === false) ? false : $callable($value);
229
            },
230
            null
231
        );
232
    };
233
}
234
235
/**
236
 * Groups callbacks and checks they any return true.
237
 *
238
 * @param callable(mixed):bool ...$callables
239
 * @return Closure(mixed):bool
240
 */
241
function groupOr(callable ...$callables): Closure
242
{
243
    /**
244
     * @param mixed $value
245
     * @return bool
246
     */
247
    return function ($value) use ($callables): bool {
248
        return (bool) array_reduce(
249
            $callables,
250
            function ($result, $callable) use ($value) {
251
                return (is_bool($result) && $result === true) ? true : $callable($value);
252
            },
253
            null
254
        );
255
    };
256
}
257
258
/**
259
 * Creates a callback for checking if a value has the desired scalar type.
260
 *
261
 * @param string $source Type to compare with (bool, boolean, integer, object)
262
 * @return Closure(mixed):bool
263
 */
264
function isScalar(string $source): Closure
265
{
266
    /**
267
     * @param mixed $value
268
     * @return bool
269
     */
270
    return function ($value) use ($source) {
271
        return gettype($value) === $source;
272
    };
273
}
274
275
276
277
/**
278
 * Checks if all passed have the same scalar
279
 *
280
 * @param mixed ...$variables
281
 * @return bool
282
 */
283
function sameScalar(...$variables): bool
284
{
285
    return count(
286
        array_unique(
287
            array_map('gettype', $variables)
288
        )
289
    ) === 1;
290
}
291
292
/**
293
 * Checks if all the values passed are true.
294
 *
295
 * @param bool ...$variables
296
 * @return bool
297
 */
298
function allTrue(bool ...$variables): bool
299
{
300
    foreach ($variables as $value) {
301
        if (! is_bool($value) || $value !== true) {
302
            return false;
303
        }
304
    }
305
    return true;
306
}
307
308
/**
309
 * Checks if all the values passed are true.
310
 *
311
 * @param bool ...$variables
312
 * @return bool
313
 */
314
function anyTrue(bool ...$variables): bool
315
{
316
    foreach ($variables as $value) {
317
        if (is_bool($value) && $value === true) {
318
            return true;
319
        }
320
    }
321
    return false;
322
}
323
324
/**
325
 * Checks if the passed value is a boolean and false
326
 *
327
 * @param mixed $value
328
 * @return bool
329
 */
330
function isFalse($value): bool
331
{
332
    return is_bool($value) && $value === false;
333
}
334
335
/**
336
 * Checks if the passed value is a boolean and true
337
 *
338
 * @param mixed $value
339
 * @return bool
340
 */
341
function isTrue($value): bool
342
{
343
    return is_bool($value) && $value === true;
344
}
345
346
/**
347
 * Checks if the passed value is a float or int.
348
 *
349
 * @param mixed $value
350
 * @return boolean
351
 */
352
function isNumber($value): bool
353
{
354
    return is_float($value) || is_int($value);
355
}
356
357
/**
358
 * Alias for groupOr
359
 *
360
 * @param callable(mixed):bool ...$callables
361
 * @return Closure(mixed):bool
362
 */
363
function any(callable ...$callables): Closure
364
{
365
    return groupOr(...$callables);
366
}
367
368
/**
369
 * Alias for groupAnd
370
 *
371
 * @param callable(mixed):bool ...$callables
372
 * @return Closure(mixed):bool
373
 */
374
function all(callable ...$callables): Closure
375
{
376
    return groupAnd(...$callables);
377
}
378
379
/**
380
 * Returns a callable for giving the reverse boolean response.
381
 *
382
 * @param callable(mixed):bool $callable
383
 * @return Closure(mixed):bool
384
 */
385
function not(callable $callable): Closure
386
{
387
    /**
388
     * @param mixed $value
389
     * @return bool
390
     */
391
    return function ($value) use ($callable): bool {
392
        return ! (bool) $callable($value);
393
    };
394
}
395