<?php
// https://dev.to/ianrodrigues/writing-value-objects-in-php-4acg
<?php declare(strict_types=1);

final class Price
{
    const USD = 'USD';
    const CAD = 'CAD';

    /** @var float */
    private $amount;

    /** @var string */
    private $currency;

    public function __construct(float $amount, string $currency = 'USD')
    {
        if ($amount < 0) {
            throw new \InvalidArgumentException("Amount should be a positive value: {$amount}.");
        }

        if (!in_array($currency, $this->getAvailableCurrencies())) {
            throw new \InvalidArgumentException("Currency should be a valid one: {$currency}.");
        }

        $this->amount = $amount;
        $this->currency = $currency;
    }

    private function getAvailableCurrencies(): array
    {
        return [self::USD, self::CAD];
    }

    public function getAmount(): float
    {
        return $this->amount;
    }

    public function getCurrency(): string
    {
        return $this->currency;
    }
}

final class Price
{
    // ...

    private function hasSameCurrency(Price $price): bool
    {
        return $this->currency === $price->currency;
    }

    public function sum(Price $price): self
    {
        if (!$this->hasSameCurrency($price)) {
            throw \InvalidArgumentException(
                "You can only sum values with the same currency: {$this->currency} !== {$price->currency}."
            );
        }

        return new self($this->amount + $price->amount, $this->currency);
    }
    
    
    final class Price
{
    // ...

    public function isEqualsTo(Price $price): bool
    {
        return $this->amount === $price->amount && $this->currency === $price->currency;
    }
}


final class Price
{
    // ...

    private function hash(): string
    {
        return md5("{$this->amount}{$this->currency}");
    }

    public function isEqualsTo(Price $price): bool
    {
        return $this->hash() === $price->hash();
    }
}


final class Price
{
    // ...

    public function __construct(float $amount, string $currency = 'USD')
    {
        if ($amount < 0) {
            throw new \InvalidArgumentException("Amount should be a positive value: {$amount}.");
        }

        if (!in_array($currency, $this->getAvailableCurrencies())) {
            throw new \InvalidArgumentException("Currency should be a valid one: {$currency}.");
        }

        $this->amount = $amount;
        $this->currency = $currency;
    }
}