Complex classes like QuantityValue often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use QuantityValue, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class QuantityValue extends DataValueObject { |
||
19 | |||
20 | /** |
||
21 | * The quantity's amount |
||
22 | * |
||
23 | * @var DecimalValue |
||
24 | */ |
||
25 | private $amount; |
||
26 | |||
27 | /** |
||
28 | * The quantity's unit identifier (use "1" for unitless quantities). |
||
29 | * |
||
30 | * @var string |
||
31 | */ |
||
32 | private $unit; |
||
33 | |||
34 | /** |
||
35 | * The quantity's upper bound |
||
36 | * |
||
37 | * @var DecimalValue|null |
||
38 | */ |
||
39 | private $upperBound; |
||
40 | |||
41 | /** |
||
42 | * The quantity's lower bound |
||
43 | * |
||
44 | * @var DecimalValue|null |
||
45 | */ |
||
46 | private $lowerBound; |
||
47 | |||
48 | /** |
||
49 | * Constructs a new QuantityValue object, representing the given value. |
||
50 | * |
||
51 | * @since 0.1 |
||
52 | * |
||
53 | * @param DecimalValue $amount |
||
54 | * @param string $unit A unit identifier. Must not be empty, use "1" for unit-less quantities. |
||
55 | * @param DecimalValue|null $upperBound The upper bound of the quantity, inclusive. |
||
56 | * @param DecimalValue|null $lowerBound The lower bound of the quantity, inclusive. |
||
57 | * |
||
58 | * @throws IllegalValueException |
||
59 | */ |
||
60 | public function __construct( |
||
91 | |||
92 | /** |
||
93 | * Returns a QuantityValue representing the given amount. |
||
94 | * If no upper or lower bound is given, the amount is assumed to be absolutely exact, |
||
95 | * that is, the amount itself will be used as the upper and lower bound. |
||
96 | * |
||
97 | * This is a convenience wrapper around the constructor that accepts native values |
||
98 | * instead of DecimalValue objects. |
||
99 | * |
||
100 | * @note: if the amount or a bound is given as a string, the string must conform |
||
101 | * to the rules defined by @see DecimalValue. |
||
102 | * |
||
103 | * @since 0.1 |
||
104 | * |
||
105 | * @param string|int|float|DecimalValue $amount |
||
106 | * @param string $unit A unit identifier. Must not be empty, use "1" for unit-less quantities. |
||
107 | * @param string|int|float|DecimalValue|null $upperBound |
||
108 | * @param string|int|float|DecimalValue|null $lowerBound |
||
109 | * |
||
110 | * @return QuantityValue |
||
111 | * @throws IllegalValueException |
||
112 | */ |
||
113 | public static function newFromNumber( $amount, $unit = '1', $upperBound = null, $lowerBound = null ) { |
||
125 | |||
126 | /** |
||
127 | * @see newFromNumber |
||
128 | * |
||
129 | * @deprecated since 0.1, use newFromNumber instead |
||
130 | * |
||
131 | * @param string|int|float|DecimalValue $amount |
||
132 | * @param string $unit |
||
133 | * @param string|int|float|DecimalValue|null $upperBound |
||
134 | * @param string|int|float|DecimalValue|null $lowerBound |
||
135 | * |
||
136 | * @return QuantityValue |
||
137 | */ |
||
138 | public static function newFromDecimal( $amount, $unit = '1', $upperBound = null, $lowerBound = null ) { |
||
141 | |||
142 | /** |
||
143 | * Converts $number to a DecimalValue if possible and necessary. |
||
144 | * |
||
145 | * @note: if the $number is given as a string, it must conform to the rules |
||
146 | * defined by @see DecimalValue. |
||
147 | * |
||
148 | * @param string $name The variable name to use in exception messages |
||
149 | * @param string|int|float|DecimalValue|null $number |
||
150 | * |
||
151 | * @throws IllegalValueException |
||
152 | * @throws InvalidArgumentException |
||
153 | * @return DecimalValue |
||
154 | */ |
||
155 | private static function asDecimalValue( $name, $number ) { |
||
170 | |||
171 | /** |
||
172 | * @see Serializable::serialize |
||
173 | * |
||
174 | * @since 0.1 |
||
175 | * |
||
176 | * @return string |
||
177 | */ |
||
178 | public function serialize() { |
||
194 | |||
195 | /** |
||
196 | * @see Serializable::unserialize |
||
197 | * |
||
198 | * @since 0.1 |
||
199 | * |
||
200 | * @param string $data |
||
201 | */ |
||
202 | public function unserialize( $data ) { |
||
212 | |||
213 | /** |
||
214 | * @see DataValue::getType |
||
215 | * |
||
216 | * @since 0.1 |
||
217 | * |
||
218 | * @return string |
||
219 | */ |
||
220 | public static function getType() { |
||
223 | |||
224 | /** |
||
225 | * Whether this Quantity has a known upper and lower bound. |
||
226 | * If this returns true, getUpperBound() and getLowerBound() will return a DecimalValue. |
||
227 | * If this returns false, getUpperBound() and getLowerBound() will return null. |
||
228 | * |
||
229 | * @return bool |
||
230 | */ |
||
231 | public function hasKnownBounds() { |
||
234 | |||
235 | /** |
||
236 | * @see DataValue::getSortKey |
||
237 | * |
||
238 | * @since 0.1 |
||
239 | * |
||
240 | * @return float |
||
241 | */ |
||
242 | public function getSortKey() { |
||
245 | |||
246 | /** |
||
247 | * Returns the quantity object. |
||
248 | * @see DataValue::getValue |
||
249 | * |
||
250 | * @since 0.1 |
||
251 | * |
||
252 | * @return QuantityValue |
||
253 | */ |
||
254 | public function getValue() { |
||
257 | |||
258 | /** |
||
259 | * Returns the amount represented by this quantity. |
||
260 | * |
||
261 | * @since 0.1 |
||
262 | * |
||
263 | * @return DecimalValue |
||
264 | */ |
||
265 | public function getAmount() { |
||
268 | |||
269 | /** |
||
270 | * Returns this quantity's upper bound, or null if the bounds are not known. |
||
271 | * |
||
272 | * @since 0.1 |
||
273 | * |
||
274 | * @return DecimalValue|null |
||
275 | */ |
||
276 | public function getUpperBound() { |
||
279 | |||
280 | /** |
||
281 | * Returns this quantity's lower bound, or null if the bounds are not known. |
||
282 | * |
||
283 | * @since 0.1 |
||
284 | * |
||
285 | * @return DecimalValue|null |
||
286 | */ |
||
287 | public function getLowerBound() { |
||
290 | |||
291 | /** |
||
292 | * Returns the size of the uncertainty interval. |
||
293 | * This can roughly be interpreted as "amount +/- uncertainty/2". |
||
294 | * |
||
295 | * The exact interpretation of the uncertainty interval is left to the concrete application or |
||
296 | * data point. For example, the uncertainty interval may be defined to be that part of a |
||
297 | * normal distribution that is required to cover the 95th percentile. |
||
298 | * |
||
299 | * @since 0.1 |
||
300 | * |
||
301 | * @return float|bool The uncertainty magnitude, or false if the bounds for this Quantity |
||
302 | * are not known. |
||
303 | */ |
||
304 | public function getUncertainty() { |
||
311 | |||
312 | /** |
||
313 | * Returns a DecimalValue representing the symmetrical offset to be applied |
||
314 | * to the raw amount for a rough representation of the uncertainty interval, |
||
315 | * as in "amount +/- offset". |
||
316 | * |
||
317 | * The offset is calculated as max( amount - lowerBound, upperBound - amount ). |
||
318 | * |
||
319 | * @since 0.1 |
||
320 | * |
||
321 | * @return DecimalValue|null The size of the uncertainty margin, or null if the bounds |
||
322 | * for this Quantity are not known. |
||
323 | */ |
||
324 | public function getUncertaintyMargin() { |
||
337 | |||
338 | /** |
||
339 | * Returns the order of magnitude of the uncertainty as the exponent of |
||
340 | * last significant digit in the amount-string. The value returned by this |
||
341 | * is suitable for use with @see DecimalMath::roundToExponent(). |
||
342 | * |
||
343 | * @example: if two digits after the decimal point are significant, this |
||
344 | * returns -2. |
||
345 | * |
||
346 | * @example: if the last two digits before the decimal point are insignificant, |
||
347 | * this returns 2. |
||
348 | * |
||
349 | * Note that this calculation assumes a symmetric uncertainty interval, |
||
350 | * and can be misleading. |
||
351 | * |
||
352 | * A quantity without known bounds is treated as absolutely precise in this context. |
||
353 | * |
||
354 | * @since 0.1 |
||
355 | * |
||
356 | * @return int The order of uncertainty |
||
357 | */ |
||
358 | public function getOrderOfUncertainty() { |
||
385 | |||
386 | /** |
||
387 | * Returns the number of significant figures in the amount-string, |
||
388 | * counting the decimal point, but not counting the leading sign. |
||
389 | * |
||
390 | * Note that this calculation assumes a symmetric uncertainty interval, and can be misleading |
||
391 | * |
||
392 | * @since 0.1 |
||
393 | * |
||
394 | * @return int |
||
395 | */ |
||
396 | public function getSignificantFigures() { |
||
407 | |||
408 | /** |
||
409 | * Returns the unit held by this quantity. |
||
410 | * Unit-less quantities should use "1" as their unit. |
||
411 | * |
||
412 | * @since 0.1 |
||
413 | * |
||
414 | * @return string |
||
415 | */ |
||
416 | public function getUnit() { |
||
419 | |||
420 | /** |
||
421 | * Returns a transformed value derived from this QuantityValue by applying |
||
422 | * the given transformation to the amount and the upper and lower bounds. |
||
423 | * The resulting amount and bounds are rounded to the significant number of |
||
424 | * digits. Note that for exact quantities (with at least one bound equal to |
||
425 | * the amount), no rounding is applied (since they are considered to have |
||
426 | * infinite precision). |
||
427 | * |
||
428 | * The transformation is provided as a callback, which must implement a |
||
429 | * monotonously increasing, fully differentiable function mapping a DecimalValue |
||
430 | * to a DecimalValue. Typically, it will be a linear transformation applying a |
||
431 | * factor and an offset. |
||
432 | * |
||
433 | * @param string $newUnit The unit of the transformed quantity. |
||
434 | * |
||
435 | * @param callable $transformation A callback that implements the desired transformation. |
||
436 | * The transformation will be called three times, once for the amount, once |
||
437 | * for the lower bound, and once for the upper bound. It must return a DecimalValue. |
||
438 | * The first parameter passed to $transformation is the DecimalValue to transform |
||
439 | * In addition, any extra parameters passed to transform() will be passed through |
||
440 | * to the transformation callback. |
||
441 | * |
||
442 | * @param mixed ... Any extra parameters will be passed to the $transformation function. |
||
443 | * |
||
444 | * @throws InvalidArgumentException |
||
445 | * @return QuantityValue |
||
446 | */ |
||
447 | public function transform( $newUnit, $transformation ) { |
||
498 | |||
499 | public function __toString() { |
||
514 | |||
515 | /** |
||
516 | * @see DataValue::getArrayValue |
||
517 | * |
||
518 | * @since 0.1 |
||
519 | * |
||
520 | * @return array |
||
521 | */ |
||
522 | public function getArrayValue() { |
||
539 | |||
540 | /** |
||
541 | * Constructs a new instance of the DataValue from the provided data. |
||
542 | * This can round-trip with @see getArrayValue |
||
543 | * |
||
544 | * @since 0.1 |
||
545 | * |
||
546 | * @param mixed $data |
||
547 | * |
||
548 | * @return QuantityValue |
||
549 | * @throws IllegalValueException |
||
550 | */ |
||
551 | public static function newFromArray( $data ) { |
||
569 | |||
570 | /** |
||
571 | * @see Comparable::equals |
||
572 | * |
||
573 | * @since 0.1 |
||
574 | * |
||
575 | * @param mixed $target |
||
576 | * |
||
577 | * @return bool |
||
578 | */ |
||
579 | public function equals( $target ) { |
||
587 | |||
588 | } |
||
589 |
This check looks for the bodies of
if
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
if
bodies can be removed. If you have an empty if but statements in theelse
branch, consider inverting the condition.could be turned into
This is much more concise to read.