Floats   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 83
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 25
c 1
b 0
f 0
dl 0
loc 83
rs 10
wmc 15

4 Methods

Rating   Name   Duplication   Size   Complexity  
A ensureValueInRange() 0 11 3
A ensureValueNotInfiniteAndInRange() 0 11 2
B filter() 0 25 7
A fromString() 0 13 3
1
<?php
2
3
namespace TraderInteractive\Filter;
4
5
use TraderInteractive\Exceptions\FilterException;
6
7
/**
8
 * A collection of filters for floats.
9
 */
10
final class Floats
11
{
12
    /**
13
     * Filters $value to a float strictly.
14
     *
15
     * The return value is the float, as expected by the \TraderInteractive\Filterer class.
16
     *
17
     * @param mixed $value     The value to filter to a float.
18
     * @param bool  $allowNull Set to true if NULL values are allowed. The filtered result of a NULL value is NULL.
19
     * @param float $minValue  The minimum acceptable value.
20
     * @param float $maxValue  The maximum acceptable value.
21
     * @param bool  $castInts  Flag to cast $value to float if it is an integer.
22
     *
23
     * @return float|null The filtered value
24
     *
25
     * @throws FilterException Thrown if the given value cannot be filtered to a float.
26
     */
27
    public static function filter(
28
        $value,
29
        bool $allowNull = false,
30
        float $minValue = null,
31
        float $maxValue = null,
32
        bool $castInts = false
33
    ) {
34
        if ($allowNull === true && $value === null) {
35
            return null;
36
        }
37
38
        if (is_float($value)) {
39
            return self::ensureValueNotInfiniteAndInRange($value, $value, $minValue ?? -INF, $maxValue ?? INF);
40
        }
41
42
        if (is_int($value) && $castInts) {
43
            return self::ensureValueNotInfiniteAndInRange($value, (float)$value, $minValue ?? -INF, $maxValue ?? INF);
44
        }
45
46
        if (is_string($value)) {
47
            $floatValue = self::fromString($value);
48
            return self::ensureValueNotInfiniteAndInRange($value, $floatValue, $minValue ?? -INF, $maxValue ?? INF);
49
        }
50
51
        throw new FilterException('"' . var_export($value, true) . '" $value is not a string');
52
    }
53
54
    private static function fromString(string $value) : float
55
    {
56
        $value = strtolower(trim($value));
57
        if (!is_numeric($value)) {
58
            throw new FilterException("{$value} does not pass is_numeric");
59
        }
60
61
        //This is the only case (that we know of) where is_numeric does not return correctly cast-able float
62
        if (strpos($value, 'x') !== false) {
63
            throw new FilterException("{$value} is hex format");
64
        }
65
66
        return (float)$value;
67
    }
68
69
    private static function ensureValueNotInfiniteAndInRange(
70
        $unfilteredValue,
71
        float $floatValue,
72
        float $minValue,
73
        float $maxValue
74
    ) : float {
75
        if (is_infinite($floatValue)) {
76
            throw new FilterException("{$unfilteredValue} overflow");
77
        }
78
79
        return self::ensureValueInRange($floatValue, $minValue, $maxValue);
80
    }
81
82
    private static function ensureValueInRange(float $value, float $minValue, float $maxValue) : float
83
    {
84
        if ($value < $minValue) {
85
            throw new FilterException("{$value} is less than {$minValue}");
86
        }
87
88
        if ($value > $maxValue) {
89
            throw new FilterException("{$value} is greater than {$maxValue}");
90
        }
91
92
        return $value;
93
    }
94
}
95