Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
78.57% covered (warning)
78.57%
11 / 14
CRAP
90.24% covered (success)
90.24%
37 / 41
PhpCalculator
0.00% covered (danger)
0.00%
0 / 1
78.57% covered (warning)
78.57%
11 / 14
23.49
90.24% covered (success)
90.24%
37 / 41
 supported
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 compare
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
1 / 1
 add
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 subtract
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 multiply
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 divide
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 ceil
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 floor
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 absolute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
3 / 3
 round
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
11 / 11
 share
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 assertIntegerBounds
0.00% covered (danger)
0.00%
0 / 1
3.58
60.00% covered (warning)
60.00%
3 / 5
 castInteger
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 assertInteger
0.00% covered (danger)
0.00%
0 / 1
2.15
66.67% covered (warning)
66.67%
2 / 3
<?php
namespace Money\Calculator;
use Money\Calculator;
use Money\Money;
use Money\Number;
/**
 * @author Frederik Bosch <f.bosch@genkgo.nl>
 */
final class PhpCalculator implements Calculator
{
    /**
     * {@inheritdoc}
     */
    public static function supported()
    {
        return true;
    }
    /**
     * {@inheritdoc}
     */
    public function compare($a, $b)
    {
        return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
    }
    /**
     * {@inheritdoc}
     */
    public function add($amount, $addend)
    {
        $result = $amount + $addend;
        $this->assertInteger($result);
        return (string) $result;
    }
    /**
     * {@inheritdoc}
     */
    public function subtract($amount, $subtrahend)
    {
        $result = $amount - $subtrahend;
        $this->assertInteger($result);
        return (string) $result;
    }
    /**
     * {@inheritdoc}
     */
    public function multiply($amount, $multiplier)
    {
        $result = $amount * $multiplier;
        $this->assertIntegerBounds($result);
        return (string) $result;
    }
    /**
     * {@inheritdoc}
     */
    public function divide($amount, $divisor)
    {
        $result = $amount / $divisor;
        $this->assertIntegerBounds($result);
        return (string) $result;
    }
    /**
     * {@inheritdoc}
     */
    public function ceil($number)
    {
        return $this->castInteger(ceil($number));
    }
    /**
     * {@inheritdoc}
     */
    public function floor($number)
    {
        return $this->castInteger(floor($number));
    }
    /**
     * {@inheritdoc}
     */
    public function absolute($number)
    {
        $result = ltrim($number, '-');
        $this->assertIntegerBounds($result);
        return (string) $result;
    }
    /**
     * {@inheritdoc}
     */
    public function round($number, $roundingMode)
    {
        if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) {
            $number = Number::fromString((string) $number);
            if ($number->isHalf() === true) {
                return $this->castInteger(ceil((string) $number));
            }
            return $this->castInteger(round((string) $number, 0, Money::ROUND_HALF_UP));
        }
        if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) {
            $number = Number::fromString((string) $number);
            if ($number->isHalf() === true) {
                return $this->castInteger(floor((string) $number));
            }
            return $this->castInteger(round((string) $number, 0, Money::ROUND_HALF_DOWN));
        }
        return $this->castInteger(round($number, 0, $roundingMode));
    }
    /**
     * {@inheritdoc}
     */
    public function share($amount, $ratio, $total)
    {
        return $this->castInteger(floor($amount * $ratio / $total));
    }
    /**
     * Asserts that an integer value didn't become something else
     * (after some arithmetic operation).
     *
     * @param int $amount
     *
     * @throws \OverflowException  If integer overflow occured
     * @throws \UnderflowException If integer underflow occured
     */
    private function assertIntegerBounds($amount)
    {
        if ($amount > PHP_INT_MAX) {
            throw new \OverflowException('You overflowed the maximum allowed integer (PHP_INT_MAX)');
        } elseif ($amount < ~PHP_INT_MAX) {
            throw new \UnderflowException('You underflowed the minimum allowed integer (PHP_INT_MAX)');
        }
    }
    /**
     * Casts an amount to integer ensuring that an overflow/underflow did not occur.
     *
     * @param int $amount
     *
     * @return string
     */
    private function castInteger($amount)
    {
        $this->assertIntegerBounds($amount);
        return (string) intval($amount);
    }
    /**
     * Asserts that integer remains integer after arithmetic operations.
     *
     * @param int $amount
     */
    private function assertInteger($amount)
    {
        if (filter_var($amount, FILTER_VALIDATE_INT) === false) {
            throw new \UnexpectedValueException('The result of arithmetic operation is not an integer');
        }
    }
}