thousands = $thousands; $this->decimal = $decimal; $this->value = \is_int($value) ? $value : self::toInt((string) $value, $thousands, $decimal); } /** * FloatInt to int. * * @param string $value FloatInt value * @param string $thousands Thousands character * @param string $decimal Decimal character * * @return int * * @throws \Exception this exception is thrown if an internal explode or substr error occurs * * @since 1.0.0 */ public static function toInt(string $value, string $thousands = ',', string $decimal = '.') : int { $newValue = $value; $len = \strlen($value); $decimalPos = \strrpos($value, $decimal); if ($decimalPos === false) { $decimalPos = $len - 1; } $newValue = \str_pad($newValue, 4 - (- $decimalPos - 1), '0'); $newValue = \str_replace([$thousands, $decimal], ['', ''], $newValue); $newValue = \ltrim($newValue, '0'); return (int) $newValue; } /** * Set localization. * * @param string $thousands Thousands separator * @param string $decimal Decimal separator * * @return FloatInt * * @since 1.0.0 */ public function setLocalization(string $thousands = ',', string $decimal = '.') : self { $this->thousands = $thousands; $this->decimal = $decimal; return $this; } /** * Set value by string. * * @param string $value FloatInt value * * @return FloatInt * * @since 1.0.0 */ public function setString(string $value) : self { $this->value = self::toInt($value, $this->thousands, $this->decimal); return $this; } /** * Returns the value as float * * @return float * * @since 1.0.0 */ public function getNormalizedValue() : float { return $this->value / self::DIVISOR; } /** * Get money. * * @param null|int $decimals Precision (null = auto decimals) * * @return string * * @throws \Exception this exception is thrown if an internal substr error occurs * * @since 1.0.0 */ public function getAmount(?int $decimals = 2) : string { $value = $this->value === 0 ? \str_repeat('0', self::MAX_DECIMALS) : (string) \round($this->value, -self::MAX_DECIMALS + $decimals); $left = \substr($value, 0, -self::MAX_DECIMALS); /** @var string $left */ $left = $left === false ? '0' : $left; $right = \substr($value, -self::MAX_DECIMALS); if ($right === false) { throw new \Exception(); // @codeCoverageIgnore } $decimals ??= \strlen(\rtrim($right, '0')); return $decimals > 0 ? \number_format((float) $left, 0, $this->decimal, $this->thousands) . $this->decimal . \substr($right, 0, $decimals) : \str_pad($left, 1, '0'); } /** * Get money. * * @param null|int $decimals Precision (null = auto decimals) * * @return string * * @throws \Exception this exception is thrown if an internal substr error occurs * * @since 1.0.0 */ public function getFloat(?int $decimals = 2) : string { $value = $this->value === 0 ? \str_repeat('0', self::MAX_DECIMALS) : (string) \round($this->value, -self::MAX_DECIMALS + $decimals); $left = \substr($value, 0, -self::MAX_DECIMALS); /** @var string $left */ $left = $left === false ? '0' : $left; $right = \substr($value, -self::MAX_DECIMALS); if ($right === false) { throw new \Exception(); // @codeCoverageIgnore } $decimals ??= \strlen(\rtrim($right, '0')); return $decimals > 0 ? \number_format((float) $left, 0, $this->decimal, '') . $this->decimal . \substr($right, 0, $decimals) : \str_pad($left, 1, '0'); } /** * Add money. * * @param int|float|string|FloatInt $value Value to add * * @return FloatInt * * @since 1.0.0 */ public function add(int | float | string | self $value) : self { if (\is_string($value) || \is_float($value)) { $this->value += self::toInt((string) $value, $this->thousands, $this->decimal); } elseif (\is_int($value)) { $this->value += $value; } else { $this->value += $value->getInt(); } return $this; } /** * Get money value. * * @return int * * @since 1.0.0 */ public function getInt() : int { return $this->value; } /** * Sub money. * * @param int|float|string|FloatInt $value Value to subtract * * @return FloatInt * * @since 1.0.0 */ public function sub(int | float | string | self $value) : self { if (\is_string($value) || \is_float($value)) { $this->value -= self::toInt((string) $value, $this->thousands, $this->decimal); } elseif (\is_int($value)) { $this->value -= $value; } else { $this->value -= $value->getInt(); } return $this; } /** * Mult. * * @param int|float $value Value to multiply with * * @return FloatInt * * @since 1.0.0 */ public function mult(int | float $value) : self { $this->value = (int) ($this->value * $value); return $this; } /** * Div. * * @param int|float $value Value to divide by * * @return FloatInt * * @since 1.0.0 */ public function div(int | float $value) : self { $this->value = (int) ($this->value / $value); return $this; } /** * Abs. * * @return FloatInt * * @since 1.0.0 */ public function abs() : self { $this->value = \abs($this->value); return $this; } /** * Power. * * @param int|float $value Value to power * * @return FloatInt * * @since 1.0.0 */ public function pow(int | float $value) : self { $this->value = (int) ($this->value ** $value); return $this; } /** * Searialze. * * @return string * * @since 1.0.0 */ public function serialize() : string { return (string) $this->getInt(); } /** * Unserialize. * * @param int|string $value Value to unserialize * * @return void * * @since 1.0.0 */ public function unserialize(mixed $value) : void { $this->setInt((int) $value); } /** * Set money value. * * @param int $value Value * * @return FloatInt * * @since 1.0.0 */ public function setInt(int $value) : self { $this->value = $value; return $this; } /** * Identify the numeric format of a string * * @param string $str String representation * * @return null|array * * @since 1.0.0 */ public static function identifyNumericFormat(string $str) : ?array { $commaPos = \strrpos($str, ','); $periodPos = \strrpos($str, '.'); if ($commaPos !== false && $periodPos !== false) { return [ 'thousands' => $commaPos < $periodPos ? ',' : '.', 'decimal' => $commaPos < $periodPos ? '.' : ',', ]; } elseif ($commaPos === false && $periodPos === false) { return null; } // Back to normal cases $isComma = $commaPos !== false ? $commaPos + 3 === \strlen($str) : $periodPos + 3 !== \strlen($str); return [ 'thousands' => $isComma ? '.' : ',', 'decimal' => $isComma ? ',' : '.', ]; } }