Skip to content

Instantly share code, notes, and snippets.

@paulschwarz
Last active December 19, 2015 05:08
Show Gist options
  • Save paulschwarz/5901687 to your computer and use it in GitHub Desktop.
Save paulschwarz/5901687 to your computer and use it in GitHub Desktop.
<?php
namespace spec\SO\Entity;
use
PHPSpec2\ObjectBehavior,
SO\Entity\Money as M;
class Money extends ObjectBehavior {
function it_should_be_initializable()
{
$this->shouldHaveType('SO\Entity\Money');
}
function let()
{
$this->beConstructedWith('99.9900');
}
function it_represents_a_monetary_amount()
{
$this()->shouldBe('99.9900');
}
function it_adds()
{
$result = $this->add(new M('11.11'));
$result()->shouldBe('111.1000');
}
function it_subtracts()
{
$result = $this->subtract(new M('11.11'));
$result()->shouldBe('88.8800');
}
function it_multiplies()
{
$result = $this->multiply(1.16);
$result()->shouldBe('115.9884');
}
function it_divides()
{
$result = $this->divide(1.16);
$result()->shouldBe('86.1983');
}
function it_formats()
{
// 86.1983
$this->divide(1.16)->format()->shouldBe('86.20');
}
function it_pretty_formats()
{
// 86.1983
$this->divide(1.16)->format(TRUE)->shouldBe('86.20');
}
function it_cannot_pretty_format()
{
// 100.0000
$this->add(new M(0.01))->format(TRUE)->shouldBe('100');
}
function it_formats_thousands()
{
$this->multiply(11111)->format()->shouldBe('1,110,988.89');
}
}
<?php
namespace SO\Entity;
class Money {
const PRECISION = 4;
protected
$integer_representation,
$decimal_separator,
$thousands_separator;
public function __construct($amount, $decimal_separator = '.', $thousands_separator = ',')
{
$this->integer_representation = ((double) $amount) * $this->representation_factor();
$this->decimal_separator = $decimal_separator;
$this->thousands_separator = $thousands_separator;
}
public function __invoke()
{
return $this->__to_string();
}
public function __to_string()
{
return number_format($this->integer_representation / $this->representation_factor(),
self::PRECISION, $this->decimal_separator, '');
}
public function add(Money $other)
{
$this->integer_representation += $other->integer_representation;
return $this;
}
public function subtract(Money $other)
{
$this->integer_representation -= $other->integer_representation;
return $this;
}
public function multiply($factor)
{
$this->integer_representation *= $factor;
return $this;
}
public function divide($divisor)
{
$this->integer_representation /= $divisor;
return $this;
}
public function format($pretty = FALSE)
{
$formatted = number_format($this(), 2, $this->decimal_separator, $this->thousands_separator);
if ($pretty && preg_match('/\.00$/', $formatted))
{
$formatted = number_format($this(), 0, $this->decimal_separator, $this->thousands_separator);
}
return $formatted;
}
private function representation_factor()
{
return 10 ^ Money::PRECISION;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment