Numeric::ensure()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 16
rs 9.2
cc 4
eloc 10
nc 3
nop 1
1
<?php
2
namespace nochso\Omni;
3
4
/**
5
 * Numeric validates and converts mixed types to numeric types.
6
 */
7
class Numeric {
8
	/**
9
	 * Ensure integer or or float value by safely converting.
10
	 *
11
	 * Safe conversions to int or float:
12
	 *
13
	 * ```
14
	 * '-1'    => -1
15
	 * '+00.0' => 0.0
16
	 * '1'     => 1
17
	 * ' 1 '    => 1
18
	 * '01'    => 1
19
	 * '0.1'   => 0.1
20
	 * '.1'    => 0.1
21
	 * ```
22
	 *
23
	 * Invalid conversions:
24
	 *
25
	 * ```
26
	 * 'x'
27
	 * '0a'
28
	 * ''
29
	 * '-'
30
	 * ' '
31
	 * '0+1'
32
	 * '.'
33
	 * ','
34
	 * ```
35
	 *
36
	 * @param mixed $value
37
	 *
38
	 * @throws \InvalidArgumentException If the value could not be safely converted to int or float.
39
	 *
40
	 * @return int|float
41
	 */
42
	public static function ensure($value) {
43
		if (is_int($value) || is_float($value)) {
44
			return $value;
45
		}
46
		$value = trim($value);
47
		if (is_numeric($value)) {
48
			// Results in either int or float
49
			return $value + 0;
50
		}
51
		throw new \InvalidArgumentException(
52
			sprintf(
53
				'Expecting value of type int, float or compatible, got variable of type %s instead.',
54
				Type::summarize($value)
55
			)
56
		);
57
	}
58
59
	/**
60
	 * ensureInteger values by safely converting.
61
	 *
62
	 * These are safe conversions because no information is lost:
63
	 *
64
	 * ```
65
	 * 1      => 1
66
	 * '1.00' => 1
67
	 * '1'    => 1
68
	 * '+1'   => 1
69
	 * ```
70
	 *
71
	 * These are invalid conversions because information would be lost:
72
	 *
73
	 * ```
74
	 * 0.1
75
	 * '0.1'
76
	 * '.1'
77
	 * ```
78
	 *
79
	 * If you don't care about this, you should cast to int instead: `(int)$value`
80
	 *
81
	 * @param mixed $value
82
	 *
83
	 * @throws \InvalidArgumentException If floating point information would be lost, i.e. it does not look like an integer.
84
	 *
85
	 * @return int
86
	 */
87
	public static function ensureInteger($value) {
88
		$numeric = self::ensure($value);
89
		if ((double) (int) $numeric !== (double) $numeric) {
90
			throw new \InvalidArgumentException(
91
				sprintf(
92
					"Could not safely convert value '%s' of type '%s' to integer because of trailing decimal places.",
93
					$value,
94
					Type::summarize($value)
95
				)
96
			);
97
		}
98
		return (int) $numeric;
99
	}
100
101
	/**
102
	 * ensureFloat values by safely converting.
103
	 *
104
	 * For example the following conversions are safe:
105
	 *
106
	 * ```
107
	 * '0'     => 0.0
108
	 * '0.0'   => 0.0
109
	 * '0.1'   => 0.1
110
	 *  '-5.1' => 5.1
111
	 * ```
112
	 *
113
	 * @param mixed $value
114
	 *
115
	 * @throws \InvalidArgumentException If value could not be safely converted to float.
116
	 *
117
	 * @return float
118
	 */
119
	public static function ensureFloat($value) {
120
		return (double) self::ensure($value);
121
	}
122
}
123