1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace rdx\units; |
4
|
|
|
|
5
|
|
|
use rdx\units\exceptions\ConversionException; |
6
|
|
|
|
7
|
|
|
abstract class Quantity { |
8
|
|
|
|
9
|
|
|
// The sub class must set these, since every Quantity has different units |
10
|
|
|
// const BASE_UNIT = 'l'; |
11
|
|
|
|
12
|
|
|
// static public $default_unit = self::BASE_UNIT; |
|
|
|
|
13
|
|
|
// static public $units = array(); |
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Convert without the bother of an object |
17
|
|
|
*/ |
18
|
|
|
static public function convert( $amount, $fromUnit, $toUnit ) { |
19
|
|
|
$quantity = new static($amount, $fromUnit); |
20
|
|
|
return $quantity->to($toUnit); |
21
|
|
|
} |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Throw a ConversionException if the given unit isn't valid for the called class |
25
|
|
|
*/ |
26
|
|
|
static public function validateUnit( &$unit ) { |
27
|
|
|
if ( !static::validUnit($unit) ) { |
28
|
|
|
$quantity = (new \ReflectionClass(get_called_class()))->getShortName(); |
29
|
|
|
throw new ConversionException("Can't import '$quantity' as '$unit'."); |
30
|
|
|
} |
31
|
|
|
} |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Check if the given unit is valid for the called class |
35
|
|
|
*/ |
36
|
|
|
static public function validUnit( &$unit ) { |
37
|
|
|
if ( $unit === 'base' ) { |
38
|
|
|
$unit = static::BASE_UNIT; |
39
|
|
|
return true; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
$units = static::$units; |
43
|
|
|
if ( isset($units[0]) ) { |
44
|
|
|
return in_array($unit, $units); |
45
|
|
|
} |
46
|
|
|
return isset($units[$unit]); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
|
50
|
|
|
|
51
|
|
|
public $original_unit = ''; |
52
|
|
|
public $unit = ''; |
53
|
|
|
public $amount = 0; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* |
57
|
|
|
*/ |
58
|
|
|
public function __construct( $amount, $unit = null, $convertToDefault = true ) { |
59
|
|
|
// Invalid unit! |
60
|
|
|
if ( $unit ) { |
61
|
|
|
static::validateUnit($unit); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
$this->amount = $amount; |
65
|
|
|
$this->unit = $unit ?: $this::$default_unit; |
66
|
|
|
|
67
|
|
|
$this->original_unit = $this->unit; |
68
|
|
|
|
69
|
|
|
// Convert incoming unit into storage unit |
70
|
|
|
if ( $convertToDefault && $this->unit != $this::$default_unit ) { |
71
|
|
|
$this->amount = $this->to($this::$default_unit); |
72
|
|
|
$this->unit = $this::$default_unit; |
73
|
|
|
} |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Convert object amount to another unit, and return, don't save |
78
|
|
|
*/ |
79
|
|
|
public function to( $toUnit ) { |
80
|
|
|
static::validateUnit($toUnit); |
81
|
|
|
|
82
|
|
|
return $this->convertor($toUnit); |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* The convertor heart, that every sub class needs |
87
|
|
|
*/ |
88
|
|
|
abstract protected function convertor( $toUnit ); |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* The default convertor, using the Quantity's conversion table |
92
|
|
|
*/ |
93
|
|
|
protected function convertUsingTable( $toUnit ) { |
94
|
|
|
$this::validateUnit($toUnit); |
95
|
|
|
|
96
|
|
|
$amount = $this->amount; |
97
|
|
|
|
98
|
|
|
// First convert from `$this->unit` to `BASE_UNIT` |
99
|
|
|
$factor = $this::$units[$this->unit]; |
100
|
|
|
$amount = $factor < 0 ? -$factor / $amount : $amount * $factor; |
101
|
|
|
|
102
|
|
|
// Then convert from `BASE_UNIT` to `$toUnit` |
103
|
|
|
$factor = $this::$units[$toUnit]; |
104
|
|
|
$amount = $factor < 0 ? -$factor / $amount : $amount / $factor; |
105
|
|
|
|
106
|
|
|
return $amount; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* Advanded convertor, using unit-base-unit methods |
111
|
|
|
*/ |
112
|
|
|
protected function convertUsingMethods( $toUnit ) { |
113
|
|
|
$amount = $this->amount; |
114
|
|
|
|
115
|
|
|
if ( $this->unit != $this::BASE_UNIT ) { |
116
|
|
|
$amount = call_user_func(array($this, $this->unit . 'to' . $this::BASE_UNIT), $amount); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
if ( $this::BASE_UNIT != $toUnit ) { |
120
|
|
|
$amount = call_user_func(array($this, $this::BASE_UNIT . 'to' . $toUnit), $amount); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
return $amount; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Convert the object to another standard unit |
128
|
|
|
*/ |
129
|
|
|
public function convertTo( $unit ) { |
130
|
|
|
$this->amount = $this->to($unit); |
131
|
|
|
$this->unit = $unit; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Return this quantity in all known units |
136
|
|
|
*/ |
137
|
|
|
public function all() { |
138
|
|
|
$all = array(); |
139
|
|
|
foreach ( $this::$units as $unit => $conversion ) { |
140
|
|
|
if ( is_int($unit) ) { |
141
|
|
|
$unit = $conversion; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
$all[$unit] = $this->to($unit); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
return $all; |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
} |
151
|
|
|
|
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.