Complex classes like Decimal 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 Decimal, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 35 | class Decimal implements IEqualable |
||
|
|
|||
| 36 | { |
||
| 37 | /** Maximal number of decimal digits considered by PostgreSQL. */ |
||
| 38 | const SCALE_LIMIT = 16383; |
||
| 39 | /** |
||
| 40 | * Minimal number of significant digits for inexact calculations, like division or square root. It reflects the |
||
| 41 | * behaviour of PostgreSQL. |
||
| 42 | */ |
||
| 43 | const MIN_SIG_DIGITS = 16; |
||
| 44 | |||
| 45 | /** @var string|null string of decimal digits, including the sign and decimal point; null for the not-a-number */ |
||
| 46 | private $val; |
||
| 47 | /** @var int number of decimal digits in the fractional part, to the right of the decimal point (if any) */ |
||
| 48 | private $scale; |
||
| 49 | |||
| 50 | /** |
||
| 51 | * @param string|int|float|Decimal|object $decimalNumber the value of the decimal number; |
||
| 52 | * leading zeros are ignored (even after the minus sign), as |
||
| 53 | * well as leading and trailing whitespace; |
||
| 54 | * if an object is passed, it gets cast to string (which works |
||
| 55 | * for {@link \GMP} objects, besides others) |
||
| 56 | * @param int|null $scale the requested scale (i.e., the number of decimal digits in the fractional part) of the |
||
| 57 | * number; |
||
| 58 | * must be non-negative, or null; |
||
| 59 | * if smaller than the scale of the given number, the number gets mathematically rounded to |
||
| 60 | * the requested scale; |
||
| 61 | * if greater than the scale of the given number, the number gets padded to have such many |
||
| 62 | * decimal places; |
||
| 63 | * if not given, it is computed from <tt>$decimalNumber</tt> automatically |
||
| 64 | * @return Decimal |
||
| 65 | */ |
||
| 66 | public static function fromNumber($decimalNumber, ?int $scale = null): Decimal |
||
| 122 | |||
| 123 | /** |
||
| 124 | * Gets the not-a-number special value. Returns the same object every time. |
||
| 125 | * |
||
| 126 | * It only equals to the not-a-number, and is greater than any number value. The result of any operation is, again, |
||
| 127 | * the not-a-number. |
||
| 128 | * |
||
| 129 | * @return Decimal the not-a-number value |
||
| 130 | */ |
||
| 131 | public static function NaN(): Decimal |
||
| 139 | |||
| 140 | /** |
||
| 141 | * Gets the decimal object representing the number zero. Returns the same object every time. |
||
| 142 | * |
||
| 143 | * @return Decimal |
||
| 144 | */ |
||
| 145 | public static function zero(): Decimal |
||
| 153 | |||
| 154 | /** |
||
| 155 | * NOTE: The constructor is kept private so that extra sanity checks are performed on user input, while trusting the |
||
| 156 | * results of the operations without these extra checks. |
||
| 157 | * |
||
| 158 | * @param string|null $val |
||
| 159 | * @param int|null $scale |
||
| 160 | */ |
||
| 161 | private function __construct(?string $val, ?int $scale = null) |
||
| 241 | |||
| 242 | |||
| 243 | /** |
||
| 244 | * @return int|null number of decimal digits in the fractional part, to the right of the decimal point (if any), or |
||
| 245 | * <tt>null</tt> for the not-a-number |
||
| 246 | */ |
||
| 247 | public function getScale(): ?int |
||
| 251 | |||
| 252 | /** |
||
| 253 | * Compare this number numerically with another number. |
||
| 254 | * |
||
| 255 | * Note that using the `==` operator checks that the two {@link Decimal} objects are of the same value and scale, |
||
| 256 | * which might or might not be desired. Such a difference only arises in the trailing fractional zero digits, |
||
| 257 | * though. |
||
| 258 | * |
||
| 259 | * @param string|int|float|Decimal|object $number number to compare this number with |
||
| 260 | * @return bool|null whether this number numerically equals to <tt>$number</tt>; |
||
| 261 | * <tt>null</tt> for <tt>null</tt> input |
||
| 262 | */ |
||
| 263 | public function equals($number): ?bool |
||
| 270 | |||
| 271 | /** |
||
| 272 | * @param string|int|float|Decimal|object $number |
||
| 273 | * @return bool <tt>true</tt> iff this number is numerically less than <tt>$number</tt> |
||
| 274 | */ |
||
| 275 | public function lessThan($number): bool |
||
| 279 | |||
| 280 | /** |
||
| 281 | * @param string|int|float|Decimal|object $number |
||
| 282 | * @return bool <tt>true</tt> iff this number is numerically greater than <tt>$number</tt> |
||
| 283 | */ |
||
| 284 | public function greaterThan($number): bool |
||
| 288 | |||
| 289 | /** |
||
| 290 | * @param string|int|float|Decimal|object $number number to compare this number with |
||
| 291 | * @return int -1, 0, or 1 if this number is numerically less than, equal to, or greater than <tt>$number</tt> |
||
| 292 | */ |
||
| 293 | public function compareTo($number): int |
||
| 308 | |||
| 309 | /** |
||
| 310 | * @return bool whether this is a not-a-number |
||
| 311 | */ |
||
| 312 | public function isNaN(): bool |
||
| 316 | |||
| 317 | /** |
||
| 318 | * @return bool whether this is zero |
||
| 319 | */ |
||
| 320 | public function isZero(): bool |
||
| 324 | |||
| 325 | /** |
||
| 326 | * @return bool whether this is a positive number |
||
| 327 | */ |
||
| 328 | public function isPositive(): bool |
||
| 332 | |||
| 333 | /** |
||
| 334 | * @return bool whether this is a negative number |
||
| 335 | */ |
||
| 336 | public function isNegative(): bool |
||
| 340 | |||
| 341 | /** |
||
| 342 | * @return bool whether this is an integer, i.e., a number without decimal part (or the decimal part equal to zero) |
||
| 343 | */ |
||
| 344 | public function isInteger(): bool |
||
| 364 | |||
| 365 | /** |
||
| 366 | * @param string|int|float|Decimal|object $augend |
||
| 367 | * @return Decimal a new decimal number, representing the result of sum of this and the given number |
||
| 368 | */ |
||
| 369 | public function add($augend): Decimal |
||
| 381 | |||
| 382 | /** |
||
| 383 | * @param string|int|float|Decimal|object $subtrahend |
||
| 384 | * @return Decimal a new decimal number, representing the result of subtraction of this and the given number |
||
| 385 | */ |
||
| 386 | public function subtract($subtrahend): Decimal |
||
| 398 | |||
| 399 | /** |
||
| 400 | * @param string|int|float|Decimal|object $multiplicand |
||
| 401 | * @return Decimal a new decimal number, representing the result of multiplication of this and the given number |
||
| 402 | */ |
||
| 403 | public function multiply($multiplicand): Decimal |
||
| 415 | |||
| 416 | /** |
||
| 417 | * @param string|int|float|Decimal|object $divisor |
||
| 418 | * @return Decimal a new decimal number, representing the result of division of this number with the given number |
||
| 419 | * @throws \RuntimeException if <tt>$divisor</tt> is zero |
||
| 420 | */ |
||
| 421 | public function divide($divisor): Decimal |
||
| 433 | |||
| 434 | /** |
||
| 435 | * @param string|int|float|Decimal|object $modulus |
||
| 436 | * @return Decimal remainder of this number divided by <tt>$modulus</tt> |
||
| 437 | * @throws \RuntimeException if <tt>$modulus</tt> is zero |
||
| 438 | */ |
||
| 439 | public function mod($modulus): Decimal |
||
| 462 | |||
| 463 | /** |
||
| 464 | * @todo more precise calculation of fractional powers - now only double precision is used |
||
| 465 | * @param string|int|float|Decimal|object $power |
||
| 466 | * @return Decimal this number powered to <tt>$number</tt> |
||
| 467 | * @throws \RuntimeException if this number is negative while <tt>$power</tt> is non-integer (that would lead to a |
||
| 468 | * complex result) |
||
| 469 | */ |
||
| 470 | public function pow($power): Decimal |
||
| 492 | |||
| 493 | /** |
||
| 494 | * @return Decimal the absolute value of this number |
||
| 495 | */ |
||
| 496 | public function abs(): Decimal |
||
| 504 | |||
| 505 | /** |
||
| 506 | * @return Decimal a new decimal number, representing the negative value of this number |
||
| 507 | */ |
||
| 508 | public function negate(): Decimal |
||
| 518 | |||
| 519 | /** |
||
| 520 | * Computes the exact factorial of this number. |
||
| 521 | * Only defined on numbers of scale zero, i.e., those without decimal part, and on the not-a-number. |
||
| 522 | * |
||
| 523 | * In conformance with PostgreSQL, the factorial of non-positive numbers is defined to be 1. |
||
| 524 | * |
||
| 525 | * @return Decimal the factorial of this number |
||
| 526 | * @throws UndefinedOperationException if this number is neither a zero-scale number nor the not-a-number |
||
| 527 | */ |
||
| 528 | public function factorial(): Decimal |
||
| 551 | |||
| 552 | /** |
||
| 553 | * @param int $scale number of decimal places to round this number to; may be negative to round to higher orders |
||
| 554 | * @return Decimal a new decimal number, representing this number rounded to <tt>$scale</tt> decimal places |
||
| 555 | */ |
||
| 556 | public function round(int $scale = 0): Decimal |
||
| 560 | |||
| 561 | /** |
||
| 562 | * @return Decimal largest integer not greater than this number |
||
| 563 | */ |
||
| 564 | public function floor(): Decimal |
||
| 584 | |||
| 585 | /** |
||
| 586 | * @return Decimal smallest integer not less than this number |
||
| 587 | */ |
||
| 588 | public function ceil(): Decimal |
||
| 608 | |||
| 609 | /** |
||
| 610 | * @param string|int|float|Decimal|object $number |
||
| 611 | * @return Decimal the greater of this number and <tt>$number</tt>, preferably this number if numerically equal |
||
| 612 | */ |
||
| 613 | public function max($number): Decimal |
||
| 622 | |||
| 623 | /** |
||
| 624 | * @param string|int|float|Decimal|object $number |
||
| 625 | * @return Decimal the smaller of this number and <tt>$number</tt>, preferably this number if numerically equal |
||
| 626 | */ |
||
| 627 | public function min($number): Decimal |
||
| 636 | |||
| 637 | /** |
||
| 638 | * @return Decimal a new decimal number, representing the square root of this number |
||
| 639 | * @throws UndefinedOperationException if this is a negative number |
||
| 640 | */ |
||
| 641 | public function sqrt(): Decimal |
||
| 652 | |||
| 653 | |||
| 654 | /** |
||
| 655 | * @return int|null the value of this number cast explicitly to <tt>int</tt>; |
||
| 656 | * for big numbers, this yields the maximal available integer value (i.e., <tt>PHP_INT_MAX</tt> or |
||
| 657 | * <tt>PHP_INT_MIN</tt>); |
||
| 658 | * <tt>null</tt> is returned if this is the not-a-number |
||
| 659 | */ |
||
| 660 | public function toInt(): ?int |
||
| 664 | |||
| 665 | /** |
||
| 666 | * @return float the value of this number cast explicitly to <tt>float</tt>, or the float <tt>NAN</tt> value if this |
||
| 667 | * is the not-a-number |
||
| 668 | */ |
||
| 669 | public function toFloat(): float |
||
| 673 | |||
| 674 | /** |
||
| 675 | * @return string the value of this number, or the special string <tt>'NaN'</tt> for the not-a-number value |
||
| 676 | */ |
||
| 677 | public function toString(): string |
||
| 681 | |||
| 682 | /** |
||
| 683 | * Converts the value to a {@link \GMP} object. |
||
| 684 | * |
||
| 685 | * Requires the `gmp` PHP extension. |
||
| 686 | * |
||
| 687 | * @return \GMP a {@link \GMP} object representing the same integer as this number |
||
| 688 | * @throws UndefinedOperationException if this number is not an integer, i.e., has some non-zero fractional digits |
||
| 689 | */ |
||
| 690 | public function toGMP() |
||
| 699 | |||
| 700 | public function __toString() |
||
| 704 | } |
||
| 705 |