From fdd7a6842f51ae382cb71500062e31e95b22d065 Mon Sep 17 00:00:00 2001 From: vansari Date: Wed, 28 Dec 2022 20:44:54 +0100 Subject: [PATCH 1/9] - declared strict types - Added Return Types - Remove unnecessary consts - use regex group name for more readability - cast variables to string - fixed compatibility for PHP < 8.0 with substr --- src/Decimal.php | 99 ++++++++++++++++++------------------------- tests/DecimalTest.php | 3 ++ 2 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/Decimal.php b/src/Decimal.php index 6d042e5..3f0df8c 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -1,4 +1,5 @@ compareTo($value) >= 0); } - /** - * @deprecated Use {@link greaterThanOrEquals()} instead. - * - * @param static|string|float|int $value - * - * @return bool - */ - public function greatherThanOrEquals($value): bool - { - return $this->greaterThanOrEquals($value); - } - /** * @param static|string|float|int $value * @@ -242,7 +222,7 @@ public function compareTo($value): int $decimal = static::create($value); $scale = max($this->scale(), $decimal->scale()); - return bccomp($this, $decimal, $scale); + return bccomp((string)$this, (string)$decimal, $scale); } /** @@ -253,12 +233,12 @@ public function compareTo($value): int * * @return static */ - public function add($value, ?int $scale = null) + public function add($value, ?int $scale = null): Decimal { $decimal = static::create($value); $scale = $this->resultScale($this, $decimal, $scale); - return new static(bcadd($this, $decimal, $scale)); + return new static(bcadd((string)$this, (string)$decimal, $scale)); } /** @@ -273,7 +253,7 @@ public function add($value, ?int $scale = null) * * @return int */ - protected function resultScale($a, $b, ?int $scale = null): int + protected function resultScale(Decimal $a, Decimal $b, ?int $scale = null): int { if ($scale === null) { $scale = max($a->scale(), $b->scale()); @@ -291,12 +271,12 @@ protected function resultScale($a, $b, ?int $scale = null): int * * @return static */ - public function subtract($value, ?int $scale = null) + public function subtract($value, ?int $scale = null): Decimal { $decimal = static::create($value); $scale = $this->resultScale($this, $decimal, $scale); - return new static(bcsub($this, $decimal, $scale)); + return new static(bcsub((string)$this, (string)$decimal, $scale)); } /** @@ -304,7 +284,7 @@ public function subtract($value, ?int $scale = null) * * @return static */ - public function trim() + public function trim(): Decimal { return $this->copy($this->integralPart, $this->trimDecimals($this->fractionalPart)); } @@ -338,7 +318,7 @@ public function sign(): int * * @return static */ - public function absolute() + public function absolute(): Decimal { return $this->copy($this->integralPart, $this->fractionalPart, false); } @@ -348,7 +328,7 @@ public function absolute() * * @return static */ - public function negate() + public function negate(): Decimal { return $this->copy(null, null, !$this->isNegative()); } @@ -399,14 +379,14 @@ public function isPositive(): bool * * @return static */ - public function multiply($value, ?int $scale = null) + public function multiply($value, ?int $scale = null): Decimal { $decimal = static::create($value); if ($scale === null) { $scale = $this->scale() + $decimal->scale(); } - return new static(bcmul($this, $decimal, $scale)); + return new static(bcmul((string)$this, (string)$decimal, $scale)); } /** @@ -419,14 +399,14 @@ public function multiply($value, ?int $scale = null) * * @return static */ - public function divide($value, int $scale) + public function divide($value, int $scale): Decimal { $decimal = static::create($value); if ($decimal->isZero()) { throw new DivisionByZeroError('Cannot divide by zero. Only Chuck Norris can!'); } - return new static(bcdiv($this, $decimal, $scale)); + return new static(bcdiv((string)$this, (string)$decimal, $scale)); } /** @@ -437,13 +417,13 @@ public function divide($value, int $scale) * * @return static */ - public function pow($exponent, ?int $scale = null) + public function pow($exponent, ?int $scale = null): Decimal { if ($scale === null) { $scale = $this->scale(); } - return new static(bcpow($this, (string)$exponent, $scale)); + return new static(bcpow((string)$this, (string)$exponent, $scale)); } /** @@ -453,13 +433,13 @@ public function pow($exponent, ?int $scale = null) * * @return static */ - public function sqrt(?int $scale = null) + public function sqrt(?int $scale = null): Decimal { if ($scale === null) { $scale = $this->scale(); } - return new static(bcsqrt($this, $scale)); + return new static(bcsqrt((string)$this, $scale)); } /** @@ -470,16 +450,16 @@ public function sqrt(?int $scale = null) * * @return static */ - public function mod($value, ?int $scale = null) + public function mod($value, ?int $scale = null): Decimal { if ($scale === null) { $scale = $this->scale(); } if (version_compare(PHP_VERSION, '7.2') < 0) { - return new static(bcmod($this, (string)$value)); + return new static(bcmod((string)$this, (string)$value)); } - return new static(bcmod($this, (string)$value, $scale)); + return new static(bcmod((string)$this, (string)$value, $scale)); } /** @@ -488,23 +468,23 @@ public function mod($value, ?int $scale = null) * * @return static */ - public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP) + public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): Decimal { $exponent = $scale + 1; $e = bcpow('10', (string)$exponent); switch ($roundMode) { case static::ROUND_FLOOR: - $v = bcdiv(bcadd(bcmul($this, $e, 0), $this->isNegative() ? '-9' : '0'), $e, 0); + $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-9' : '0'), $e, 0); break; case static::ROUND_CEIL: - $v = bcdiv(bcadd(bcmul($this, $e, 0), $this->isNegative() ? '0' : '9'), $e, 0); + $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '0' : '9'), $e, 0); break; case static::ROUND_HALF_UP: default: - $v = bcdiv(bcadd(bcmul($this, $e, 0), $this->isNegative() ? '-5' : '5'), $e, $scale); + $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-5' : '5'), $e, $scale); } return new static($v); @@ -515,7 +495,7 @@ public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP) * * @return static */ - public function floor() + public function floor(): Decimal { return $this->round(0, static::ROUND_FLOOR); } @@ -525,7 +505,7 @@ public function floor() * * @return static */ - public function ceil() + public function ceil(): Decimal { return $this->round(0, static::ROUND_CEIL); } @@ -539,7 +519,7 @@ public function ceil() * * @return static */ - public function truncate(int $scale = 0) + public function truncate(int $scale = 0): Decimal { if ($scale < 0) { throw new InvalidArgumentException('Scale must be >= 0.'); @@ -714,7 +694,7 @@ public function jsonSerialize(): string * * @return static */ - protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null) + protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null): Decimal { $clone = clone $this; if ($integerPart !== null) { @@ -807,16 +787,18 @@ protected function fromFloat(string $value): void */ protected function fromScientific(string $value, ?int $scale): void { - $pattern = '/^(-?)(\d+(?:' . static::RADIX_MARK . '\d*)?|' . - '[' . static::RADIX_MARK . ']' . '\d+)' . static::EXP_MARK . '(-?\d*)?$/i'; + $pattern = '/^(?-?)(?\d+(?:\.\d*)?|[.]\d+)e(?-?\d*)?$/i'; preg_match($pattern, $value, $matches); if (!$matches) { throw new InvalidArgumentException('Invalid scientific value/notation: ' . $value); } - $this->negative = $matches[1] === '-'; - $value = preg_replace('/\b\.0$/', '', $matches[2]); - $exp = (int)$matches[3]; + $this->negative = $matches['pref'] === '-'; + $value = preg_replace('/\b\.0$/', '', $matches['value']); + if (empty($value)) { + throw new RuntimeException('Value not usable.'); + } + $exp = (int)$matches['exp']; if ($exp < 0) { $this->integralPart = '0'; @@ -828,13 +810,14 @@ protected function fromScientific(string $value, ?int $scale): void $this->fractionalPart = str_pad($this->fractionalPart, $scale, '0'); } } else { - $this->integralPart = bcmul($matches[2], bcpow('10', (string)$exp)); + $this->integralPart = bcmul($matches['value'], bcpow('10', (string)$exp)); $pos = strlen((string)$this->integralPart); if (strpos($value, '.') !== false) { $pos++; } - $this->fractionalPart = rtrim(substr($value, $pos), '.'); + // Compatibility for PHP VERSION < 8.0 (substr returns string and false in Version below 8) + $this->fractionalPart = ($substr = substr($value, $pos)) ? rtrim($substr, '.') : ''; if ($scale !== null) { $this->fractionalPart = str_pad($this->fractionalPart, $scale - strlen((string)$this->integralPart), '0'); diff --git a/tests/DecimalTest.php b/tests/DecimalTest.php index 21013b0..5f6bb81 100644 --- a/tests/DecimalTest.php +++ b/tests/DecimalTest.php @@ -1,4 +1,5 @@ Date: Wed, 28 Dec 2022 20:59:03 +0100 Subject: [PATCH 2/9] - fixed tests after strict mode declaration --- tests/DecimalTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/DecimalTest.php b/tests/DecimalTest.php index 5f6bb81..1706098 100644 --- a/tests/DecimalTest.php +++ b/tests/DecimalTest.php @@ -606,7 +606,7 @@ public function testRound($value, int $scale, string $expected): void */ protected function assertNativeRound(string $expected, $value, int $scale, int $roundMode): void { - $this->assertSame((new Decimal($expected))->trim()->toString(), (string)round($value, $scale, $roundMode)); + $this->assertSame((new Decimal($expected))->trim()->toString(), (string)round((float)$value, $scale, $roundMode)); } /** @@ -655,7 +655,7 @@ public function testFloor($value, string $expected): void */ protected function assertNativeFloor(string $expected, $value): void { - $this->assertSame($expected, (string)floor($value)); + $this->assertSame($expected, (string)floor((float)$value)); } /** @@ -702,7 +702,7 @@ public function testCeil($value, string $expected): void */ protected function assertNativeCeil(string $expected, $value): void { - $this->assertSame($expected, (string)ceil($value)); + $this->assertSame($expected, (string)ceil((float)$value)); } /** From a219106ff16ff1d01475cfea26348278a915ab1b Mon Sep 17 00:00:00 2001 From: vansari Date: Wed, 28 Dec 2022 21:06:43 +0100 Subject: [PATCH 3/9] - fixed some CS for Spryker Code Style rules --- src/Decimal.php | 40 +++++++++++++++++++++------------------- tests/DecimalTest.php | 3 ++- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/src/Decimal.php b/src/Decimal.php index 3f0df8c..f1a390d 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -1,11 +1,12 @@ resultScale($this, $decimal, $scale); @@ -271,7 +272,7 @@ protected function resultScale(Decimal $a, Decimal $b, ?int $scale = null): int * * @return static */ - public function subtract($value, ?int $scale = null): Decimal + public function subtract($value, ?int $scale = null): self { $decimal = static::create($value); $scale = $this->resultScale($this, $decimal, $scale); @@ -284,7 +285,7 @@ public function subtract($value, ?int $scale = null): Decimal * * @return static */ - public function trim(): Decimal + public function trim(): self { return $this->copy($this->integralPart, $this->trimDecimals($this->fractionalPart)); } @@ -318,7 +319,7 @@ public function sign(): int * * @return static */ - public function absolute(): Decimal + public function absolute(): self { return $this->copy($this->integralPart, $this->fractionalPart, false); } @@ -328,7 +329,7 @@ public function absolute(): Decimal * * @return static */ - public function negate(): Decimal + public function negate(): self { return $this->copy(null, null, !$this->isNegative()); } @@ -379,7 +380,7 @@ public function isPositive(): bool * * @return static */ - public function multiply($value, ?int $scale = null): Decimal + public function multiply($value, ?int $scale = null): self { $decimal = static::create($value); if ($scale === null) { @@ -399,7 +400,7 @@ public function multiply($value, ?int $scale = null): Decimal * * @return static */ - public function divide($value, int $scale): Decimal + public function divide($value, int $scale): self { $decimal = static::create($value); if ($decimal->isZero()) { @@ -417,7 +418,7 @@ public function divide($value, int $scale): Decimal * * @return static */ - public function pow($exponent, ?int $scale = null): Decimal + public function pow($exponent, ?int $scale = null): self { if ($scale === null) { $scale = $this->scale(); @@ -433,7 +434,7 @@ public function pow($exponent, ?int $scale = null): Decimal * * @return static */ - public function sqrt(?int $scale = null): Decimal + public function sqrt(?int $scale = null): self { if ($scale === null) { $scale = $this->scale(); @@ -450,7 +451,7 @@ public function sqrt(?int $scale = null): Decimal * * @return static */ - public function mod($value, ?int $scale = null): Decimal + public function mod($value, ?int $scale = null): self { if ($scale === null) { $scale = $this->scale(); @@ -468,7 +469,7 @@ public function mod($value, ?int $scale = null): Decimal * * @return static */ - public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): Decimal + public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): self { $exponent = $scale + 1; @@ -495,7 +496,7 @@ public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): Dec * * @return static */ - public function floor(): Decimal + public function floor(): self { return $this->round(0, static::ROUND_FLOOR); } @@ -505,7 +506,7 @@ public function floor(): Decimal * * @return static */ - public function ceil(): Decimal + public function ceil(): self { return $this->round(0, static::ROUND_CEIL); } @@ -519,7 +520,7 @@ public function ceil(): Decimal * * @return static */ - public function truncate(int $scale = 0): Decimal + public function truncate(int $scale = 0): self { if ($scale < 0) { throw new InvalidArgumentException('Scale must be >= 0.'); @@ -694,7 +695,7 @@ public function jsonSerialize(): string * * @return static */ - protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null): Decimal + protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null): self { $clone = clone $this; if ($integerPart !== null) { @@ -782,6 +783,7 @@ protected function fromFloat(string $value): void * @param int|null $scale * * @throws \InvalidArgumentException + * @throws \RuntimeException * * @return void */ @@ -795,7 +797,7 @@ protected function fromScientific(string $value, ?int $scale): void $this->negative = $matches['pref'] === '-'; $value = preg_replace('/\b\.0$/', '', $matches['value']); - if (empty($value)) { + if (!is_string($value)) { throw new RuntimeException('Value not usable.'); } $exp = (int)$matches['exp']; diff --git a/tests/DecimalTest.php b/tests/DecimalTest.php index 1706098..b83d048 100644 --- a/tests/DecimalTest.php +++ b/tests/DecimalTest.php @@ -1,11 +1,12 @@ Date: Wed, 28 Dec 2022 21:38:22 +0100 Subject: [PATCH 4/9] - revert const deletion - revert signature change for resultScale - revert deletion of deprecated function --- src/Decimal.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Decimal.php b/src/Decimal.php index f1a390d..104120b 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -17,6 +17,16 @@ class Decimal implements JsonSerializable { + /** + * @var string + */ + public const EXP_MARK = 'e'; + + /** + * @var string + */ + public const RADIX_MARK = '.'; + public const ROUND_HALF_UP = PHP_ROUND_HALF_UP; /** @@ -196,6 +206,18 @@ public function greaterThanOrEquals($value): bool return ($this->compareTo($value) >= 0); } + /** + * @deprecated Use {@link greaterThanOrEquals()} instead. + * + * @param static|string|float|int $value + * + * @return bool + */ + public function greatherThanOrEquals($value): bool + { + return $this->greaterThanOrEquals($value); + } + /** * @param static|string|float|int $value * @@ -254,7 +276,7 @@ public function add($value, ?int $scale = null): self * * @return int */ - protected function resultScale(Decimal $a, Decimal $b, ?int $scale = null): int + protected function resultScale($a, $b, ?int $scale = null): int { if ($scale === null) { $scale = max($a->scale(), $b->scale()); From 3d9206dcd6af417bb57f18813456fae475875ac2 Mon Sep 17 00:00:00 2001 From: vansari Date: Wed, 28 Dec 2022 21:56:17 +0100 Subject: [PATCH 5/9] Revert "- revert const deletion" This reverts commit e8fcc321c4ad2511b7f43a9967d58f6b6aad71a8. --- src/Decimal.php | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/Decimal.php b/src/Decimal.php index 104120b..f1a390d 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -17,16 +17,6 @@ class Decimal implements JsonSerializable { - /** - * @var string - */ - public const EXP_MARK = 'e'; - - /** - * @var string - */ - public const RADIX_MARK = '.'; - public const ROUND_HALF_UP = PHP_ROUND_HALF_UP; /** @@ -206,18 +196,6 @@ public function greaterThanOrEquals($value): bool return ($this->compareTo($value) >= 0); } - /** - * @deprecated Use {@link greaterThanOrEquals()} instead. - * - * @param static|string|float|int $value - * - * @return bool - */ - public function greatherThanOrEquals($value): bool - { - return $this->greaterThanOrEquals($value); - } - /** * @param static|string|float|int $value * @@ -276,7 +254,7 @@ public function add($value, ?int $scale = null): self * * @return int */ - protected function resultScale($a, $b, ?int $scale = null): int + protected function resultScale(Decimal $a, Decimal $b, ?int $scale = null): int { if ($scale === null) { $scale = max($a->scale(), $b->scale()); From 311630fae5d685c8a6ca7aa6c14799277181e80d Mon Sep 17 00:00:00 2001 From: vansari Date: Mon, 2 Jan 2023 12:15:35 +0100 Subject: [PATCH 6/9] Changed Github Workflow to 8.1 and 8.2 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f62b732..0b63129 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.3', '8.2'] + php-version: ['8.1', '8.2'] steps: - uses: actions/checkout@v3 From 0ba26e8eff95093983e5a99df24ec9eeda6896b6 Mon Sep 17 00:00:00 2001 From: vansari Date: Mon, 2 Jan 2023 12:16:22 +0100 Subject: [PATCH 7/9] Usage of new PHP 8 functions, refactoring Code --- src/Decimal.php | 123 +++++++++++++++++++----------------------- tests/DecimalTest.php | 27 +++++----- 2 files changed, 70 insertions(+), 80 deletions(-) diff --git a/src/Decimal.php b/src/Decimal.php index f1a390d..7e7ac2e 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -13,9 +13,10 @@ use InvalidArgumentException; use JsonSerializable; use RuntimeException; +use Stringable; use TypeError; -class Decimal implements JsonSerializable +class Decimal implements JsonSerializable, Stringable { public const ROUND_HALF_UP = PHP_ROUND_HALF_UP; @@ -33,37 +34,31 @@ class Decimal implements JsonSerializable * Integral part of this decimal number. * * Value before the separator. Cannot be negative. - * - * @var string */ - protected $integralPart; + protected string $integralPart = '0'; /** * Fractional part of this decimal number. * * Value after the separator (decimals) as string. Must be numbers only. - * - * @var string */ - protected $fractionalPart; + protected string $fractionalPart = ''; /** * @var bool */ - protected $negative; + protected bool $negative = false; /** * decimal(10,6) => 6 - * - * @var int */ - protected $scale; + protected int $scale = 0; /** - * @param static|string|float|int $value + * @param object|string|float|int $value * @param int|null $scale */ - public function __construct($value, ?int $scale = null) + public function __construct(float|object|int|string $value, ?int $scale = null) { $value = $this->parseValue($value); $value = $this->normalizeValue($value); @@ -87,9 +82,9 @@ public function scale(): int * * @return string */ - protected function parseValue($value): string + protected function parseValue(mixed $value): string { - if ($value !== null && !(is_scalar($value) || method_exists($value, '__toString'))) { + if ($value !== null && !(is_scalar($value) || $value instanceof Stringable)) { throw new InvalidArgumentException('Invalid value'); } @@ -137,12 +132,12 @@ protected function normalizeValue(string $value): string * Otherwise, create a new Decimal instance from the given value and return * it. * - * @param static|string|float|int $value + * @param object|string|float|int $value * @param int|null $scale * * @return static */ - public static function create($value, ?int $scale = null): self + public static function create(float|int|string|object $value, ?int $scale = null): static { if ($scale === null && $value instanceof static) { return clone $value; @@ -156,54 +151,54 @@ public static function create($value, ?int $scale = null): self * * This method is equivalent to the `==` operator. * - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return bool TRUE if this decimal is considered equal to the given value. * Equal decimal values tie-break on precision. */ - public function equals($value): bool + public function equals(float|int|string|object $value): bool { return $this->compareTo($value) === 0; } /** - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return bool */ - public function greaterThan($value): bool + public function greaterThan(float|int|string|object $value): bool { return $this->compareTo($value) > 0; } /** - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return bool */ - public function lessThan($value): bool + public function lessThan(float|int|string|object $value): bool { return $this->compareTo($value) < 0; } /** - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return bool */ - public function greaterThanOrEquals($value): bool + public function greaterThanOrEquals(float|int|string|object $value): bool { - return ($this->compareTo($value) >= 0); + return $this->compareTo($value) >= 0; } /** - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return bool */ - public function lessThanOrEquals($value): bool + public function lessThanOrEquals(float|int|string|object $value): bool { - return ($this->compareTo($value) <= 0); + return $this->compareTo($value) <= 0; } /** @@ -214,11 +209,11 @@ public function lessThanOrEquals($value): bool * - `0` if the instance is equal to $value, or * - `1` if the instance is greater than $value. * - * @param static|string|float|int $value + * @param object|string|float|int $value * * @return int */ - public function compareTo($value): int + public function compareTo(float|int|string|object $value): int { $decimal = static::create($value); $scale = max($this->scale(), $decimal->scale()); @@ -229,12 +224,12 @@ public function compareTo($value): int /** * Add $value to this Decimal and return the sum as a new Decimal. * - * @param static|string|float|int $value + * @param object|string|float|int $value * @param int|null $scale * * @return static */ - public function add($value, ?int $scale = null): self + public function add(float|int|string|object $value, ?int $scale = null): static { $decimal = static::create($value); $scale = $this->resultScale($this, $decimal, $scale); @@ -248,8 +243,8 @@ public function add($value, ?int $scale = null): self * If $scale is specified and is a valid positive integer, return it. * Otherwise, return the higher of the scales of the operands. * - * @param static $a - * @param static $b + * @param \Spryker\DecimalObject\Decimal $a + * @param \Spryker\DecimalObject\Decimal $b * @param int|null $scale * * @return int @@ -267,12 +262,12 @@ protected function resultScale(Decimal $a, Decimal $b, ?int $scale = null): int * Subtract $value from this Decimal and return the difference as a new * Decimal. * - * @param static|string|float|int $value + * @param object|string|float|int $value * @param int|null $scale * * @return static */ - public function subtract($value, ?int $scale = null): self + public function subtract(float|int|string|object $value, ?int $scale = null): static { $decimal = static::create($value); $scale = $this->resultScale($this, $decimal, $scale); @@ -285,7 +280,7 @@ public function subtract($value, ?int $scale = null): self * * @return static */ - public function trim(): self + public function trim(): static { return $this->copy($this->integralPart, $this->trimDecimals($this->fractionalPart)); } @@ -319,7 +314,7 @@ public function sign(): int * * @return static */ - public function absolute(): self + public function absolute(): static { return $this->copy($this->integralPart, $this->fractionalPart, false); } @@ -329,7 +324,7 @@ public function absolute(): self * * @return static */ - public function negate(): self + public function negate(): static { return $this->copy(null, null, !$this->isNegative()); } @@ -380,7 +375,7 @@ public function isPositive(): bool * * @return static */ - public function multiply($value, ?int $scale = null): self + public function multiply(float|int|string|Decimal $value, ?int $scale = null): static { $decimal = static::create($value); if ($scale === null) { @@ -400,7 +395,7 @@ public function multiply($value, ?int $scale = null): self * * @return static */ - public function divide($value, int $scale): self + public function divide(float|int|string|Decimal $value, int $scale): static { $decimal = static::create($value); if ($decimal->isZero()) { @@ -418,7 +413,7 @@ public function divide($value, int $scale): self * * @return static */ - public function pow($exponent, ?int $scale = null): self + public function pow(int|string|Decimal $exponent, ?int $scale = null): static { if ($scale === null) { $scale = $this->scale(); @@ -434,7 +429,7 @@ public function pow($exponent, ?int $scale = null): self * * @return static */ - public function sqrt(?int $scale = null): self + public function sqrt(?int $scale = null): static { if ($scale === null) { $scale = $this->scale(); @@ -451,7 +446,7 @@ public function sqrt(?int $scale = null): self * * @return static */ - public function mod($value, ?int $scale = null): self + public function mod(int|string|Decimal $value, ?int $scale = null): static { if ($scale === null) { $scale = $this->scale(); @@ -469,24 +464,16 @@ public function mod($value, ?int $scale = null): self * * @return static */ - public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): self + public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): static { $exponent = $scale + 1; $e = bcpow('10', (string)$exponent); - switch ($roundMode) { - case static::ROUND_FLOOR: - $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-9' : '0'), $e, 0); - - break; - case static::ROUND_CEIL: - $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '0' : '9'), $e, 0); - - break; - case static::ROUND_HALF_UP: - default: - $v = bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-5' : '5'), $e, $scale); - } + $v = match ($roundMode) { + static::ROUND_FLOOR => bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-9' : '0'), $e, 0), + static::ROUND_CEIL => bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '0' : '9'), $e, 0), + default => bcdiv(bcadd(bcmul((string)$this, $e, 0), $this->isNegative() ? '-5' : '5'), $e, $scale), + }; return new static($v); } @@ -496,7 +483,7 @@ public function round(int $scale = 0, int $roundMode = self::ROUND_HALF_UP): sel * * @return static */ - public function floor(): self + public function floor(): static { return $this->round(0, static::ROUND_FLOOR); } @@ -506,7 +493,7 @@ public function floor(): self * * @return static */ - public function ceil(): self + public function ceil(): static { return $this->round(0, static::ROUND_CEIL); } @@ -520,7 +507,7 @@ public function ceil(): self * * @return static */ - public function truncate(int $scale = 0): self + public function truncate(int $scale = 0): static { if ($scale < 0) { throw new InvalidArgumentException('Scale must be >= 0.'); @@ -608,7 +595,7 @@ public function toScientific(): string } $value = (string)$integralPart; - if (strpos($value, '.') === false) { + if (!str_contains($value, '.')) { $value .= '.'; } $value .= $this->fractionalPart; @@ -617,7 +604,7 @@ public function toScientific(): string // 00002 // 20000 $fractionalPart = $this->fractionalPart; - while (substr($fractionalPart, 0, 1) === '0') { + while (str_starts_with($fractionalPart, '0')) { $fractionalPart = substr($fractionalPart, 1); $exponent--; } @@ -695,7 +682,7 @@ public function jsonSerialize(): string * * @return static */ - protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null): self + protected function copy(?string $integerPart = null, ?string $decimalPart = null, ?bool $negative = null): static { $clone = clone $this; if ($integerPart !== null) { @@ -731,7 +718,7 @@ protected function setValue(string $value, ?int $scale): void return; } - if (strpos($value, '.') !== false) { + if (str_contains($value, '.')) { $this->fromFloat($value); return; @@ -782,8 +769,8 @@ protected function fromFloat(string $value): void * @param string $value * @param int|null $scale * - * @throws \InvalidArgumentException * @throws \RuntimeException + * @throws \InvalidArgumentException * * @return void */ @@ -815,7 +802,7 @@ protected function fromScientific(string $value, ?int $scale): void $this->integralPart = bcmul($matches['value'], bcpow('10', (string)$exp)); $pos = strlen((string)$this->integralPart); - if (strpos($value, '.') !== false) { + if (str_contains($value, '.')) { $pos++; } // Compatibility for PHP VERSION < 8.0 (substr returns string and false in Version below 8) diff --git a/tests/DecimalTest.php b/tests/DecimalTest.php index b83d048..726b6e1 100644 --- a/tests/DecimalTest.php +++ b/tests/DecimalTest.php @@ -26,7 +26,7 @@ class DecimalTest extends TestCase * * @return void */ - public function testNewObject($value, string $expected): void + public function testNewObject(mixed $value, string $expected): void { $decimal = new Decimal($value); $this->assertSame($expected, (string)$decimal); @@ -53,7 +53,7 @@ public function testNewObjectScientific(): void * * @return void */ - public function testCreate($value, string $expected): void + public function testCreate(mixed $value, string $expected): void { $decimal = Decimal::create($value); $this->assertSame($expected, (string)$decimal); @@ -112,12 +112,15 @@ public function __toString(): string * @dataProvider invalidValuesProvider * * @param mixed $value + * @param string $expectedException * * @return void */ - public function testNewObjectWithInvalidValueThrowsException($value): void - { - $this->expectException(InvalidArgumentException::class); + public function testNewObjectWithInvalidValueThrowsException( + mixed $value, + string $expectedException + ): void { + $this->expectException($expectedException); Decimal::create($value); } @@ -128,11 +131,11 @@ public function testNewObjectWithInvalidValueThrowsException($value): void public function invalidValuesProvider(): array { return [ - 'invalid string' => ['xyz'], - 'object' => [new stdClass()], - 'non-english/localized case1' => ['1018,9'], - 'non-english/localized case2' => ['1.018,9'], - 'null' => [null], + 'invalid string' => ['xyz', InvalidArgumentException::class], + 'object' => [new stdClass(), InvalidArgumentException::class], + 'non-english/localized case1' => ['1018,9', InvalidArgumentException::class], + 'non-english/localized case2' => ['1.018,9', InvalidArgumentException::class], + 'null' => [null, TypeError::class], ]; } @@ -174,7 +177,7 @@ public function truncateProvider(): array * * @return void */ - public function testIsInteger($value, bool $expected): void + public function testIsInteger(mixed $value, bool $expected): void { $decimal = Decimal::create($value); $this->assertSame($expected, $decimal->isInteger()); @@ -207,7 +210,7 @@ public function integerProvider(): array * * @return void */ - public function testIsZero($value, bool $expected): void + public function testIsZero(mixed $value, bool $expected): void { $decimal = Decimal::create($value); $this->assertSame($expected, $decimal->isZero()); From 7c84bbce0639fb7a34e39817f07bbb50b1269d5c Mon Sep 17 00:00:00 2001 From: vansari Date: Mon, 2 Jan 2023 12:33:20 +0100 Subject: [PATCH 8/9] Upgraded PHP Version which is required --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0f49095..db1dc9e 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=7.3", + "php": ">=8.0", "ext-bcmath": "*", "ext-json": "*" }, From 72eaa9d09d3cae435c81c210965cb8128de96585 Mon Sep 17 00:00:00 2001 From: vansari Date: Sun, 8 Jan 2023 18:04:04 +0100 Subject: [PATCH 9/9] Replace str_contains with older str_pos --- src/Decimal.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Decimal.php b/src/Decimal.php index 7e7ac2e..232cf42 100644 --- a/src/Decimal.php +++ b/src/Decimal.php @@ -595,7 +595,7 @@ public function toScientific(): string } $value = (string)$integralPart; - if (!str_contains($value, '.')) { + if (strpos($value, '.') === false) { $value .= '.'; } $value .= $this->fractionalPart; @@ -604,7 +604,7 @@ public function toScientific(): string // 00002 // 20000 $fractionalPart = $this->fractionalPart; - while (str_starts_with($fractionalPart, '0')) { + while (substr($fractionalPart, 0, 1) === '0') { $fractionalPart = substr($fractionalPart, 1); $exponent--; } @@ -718,7 +718,7 @@ protected function setValue(string $value, ?int $scale): void return; } - if (str_contains($value, '.')) { + if (strpos($value, '.') !== false) { $this->fromFloat($value); return; @@ -802,7 +802,7 @@ protected function fromScientific(string $value, ?int $scale): void $this->integralPart = bcmul($matches['value'], bcpow('10', (string)$exp)); $pos = strlen((string)$this->integralPart); - if (str_contains($value, '.')) { + if (strpos($value, '.') !== false) { $pos++; } // Compatibility for PHP VERSION < 8.0 (substr returns string and false in Version below 8)