v.chetkov/money

简化货币值操作的库

v0.4 2019-08-11 08:10 UTC

This package is auto-updated.

Last update: 2024-09-11 19:41:05 UTC


README

描述

该包旨在简化货币值的操作。

提供以下功能

  • 进行货币值的加、减、乘操作;
  • 将货币值平均分配到N部分;
  • 根据指定的比例分配货币值;
  • 货币转换;
  • 比较货币值(可指定允许的偏差百分比)
  • 对不同货币值的上述所有操作;

安装

composer require v.chetkov/money

配置

example.config.php

<?php 

use Chetkov\Money\Exchanger\ExchangerInterface;
use Chetkov\Money\Exchanger\RatesProvider\SimpleExchangeRatesProvider;
use Chetkov\Money\Exchanger\SimpleExchanger;

$exchangeRates = [
    'USD-RUB' => [66.34, 68.12], // Курсы покупки/продажи отличаются
    'EUR-RUB' => [72.42],        // Единый курс 
    'JPY-RUB' => [0.61],         // ...
];

return [
    'use_currency_conversation' => true,
    'exchanger_factory' => static function () use ($exchangeRates): ExchangerInterface {
        //Фабрика класса обменника
        static $instance;
        if (null === $instance) {
            $ratesProvider = SimpleExchangeRatesProvider::getInstance($exchangeRates);
            $instance = new SimpleExchanger($ratesProvider);
        }
        return $instance;
    },
];

如果参数'use_currency_conversation' => false,则在执行不同货币的Money实例的操作时将抛出OperationWithDifferentCurrenciesException异常。

否则,操作将传递给交换器(稍后介绍)以将第二个操作数转换为第一个操作数的货币。

负责存储和向交换器提供汇率的是实现ExchangeRatesProviderInterface接口的供应者类。

使用

接下来需要将上述配置加载到PackageConfig中,这是为了理解

  1. 是否启用了自动货币转换
  2. 由哪个交换器负责
  3. 哪个供应者提供数据
<?php 

use Chetkov\Money\LibConfig;

$config = require __DIR__ . 'config/example.config.php';

LibConfig::getInstance($config);

之后我们可以执行各种操作

<?php

use Chetkov\Money\Money;

$usd = Money::USD(100);
$rub = Money::RUB(200);
交换
echo $usd->exchange(CurrencyEnum::RUB);
// Result: {"amount":6634,"currency":"RUB"}
添加
$additionResult = $usd->add($rub);
echo $additionResult; 
// Result: {"amount":103.01,"currency":"USD"}
减去
$subtractionResult = $rub->subtract($usd);
echo $subtractionResult; 
// Result: {"amount":-6434,"currency":"RUB"}
乘以
$multiplicationResult = $rub->multiple(5);
echo $multiplicationResult; 
// Result: {"amount":1000,"currency":"RUB"}
平均分配
$evenlyAllocationResult = $usd->allocateEvenly(4);
echo json_encode($evenlyAllocationResult);
// Result: 
// [
//     {"amount":25,"currency":"USD"},
//     {"amount":25,"currency":"USD"},
//     {"amount":25,"currency":"USD"},
//     {"amount":25,"currency":"USD"}
// ]

您可以传递精度舍入值(可选)

$evenlyAllocationResult = $usd->allocateEvenly(3, 4);
echo json_encode($evenlyAllocationResult);
// Result: 
// [
//     {"amount":33.3333,"currency":"USD"},
//     {"amount":33.3333,"currency":"USD"},
//     {"amount":33.3334,"currency":"USD"}
// ]
按比例分配
$proportionallyAllocationResult = $usd->allocateProportionally([0.18, 0.32, 0.5, 0.3, 1]);
echo json_encode($proportionallyAllocationResult);
// Result: 
// [
//     {"amount":18,"currency":"USD"},
//     {"amount":32,"currency":"USD"},
//     {"amount":50,"currency":"USD"},
//     {"amount":30,"currency":"USD"},
//     {"amount":100,"currency":"USD"}
// ]
小于
$rub->lessThan($usd); // true
大于
$usd->moreThan($rub); // true
等于
$usd->equals($rub); // false

或跨货币的相等性/相对相等性检查。

  • $isCrossCurrenciesComparison - 跨货币比较标志(bool)
  • $allowableDeviationPercent - 允许的偏差百分比(float: 0.0 .. 100.0)
$rub = Money::RUB(200);
$usd = Money::USD(3.015);

$isCrossCurrenciesComparison = true;
$rub->equals($usd, $isCrossCurrenciesComparison); // false

$allowableDeviationPercent = 0.5;
$rub->equals($usd, $isCrossCurrenciesComparison, $allowableDeviationPercent); // true

交换器

您可以使用现有的交换器类

1 - SimpleExchanger

  • 从供应者获取汇率;
  • 搜索所需的货币对(如果不在列表中则抛出ExchangeRateWasNotFoundException异常);
  • 执行交换并返回新的Money实例;

2 - GraphRatesSearchingExchangerDecorator

  • 装饰任何其他交换器类;
  • 首先将工作委托给被装饰的对象并捕获ExchangeRateWasNotFoundException异常;
  • 如果它能够独立完成任务,则返回获取的值;
  • 否则,构建一个由现有货币对组成的图,并尝试通过其他货币进行交换路径(如果失败,则抛出ExchangeRateWasNotFoundException异常);

或者实现自己的实现。

汇率供应者

1 - SimpleExchangeRatesProvider

  • 实现Singleton模式;
  • 接受包含汇率的数组;
  • 提供设置新货币对汇率的方法;

最简单的示例:在应用程序的启动文件中实例化并加载汇率。

您可以从您的数据库中一次性加载汇率。您可以创建从第三方资源(例如货币交易所)获取汇率的方法。您可以在工作器中按指定的时间间隔更新数据。这始终取决于具体情况,由您决定 ;)

2 - CbrExchangeRatesProvider

  • 从指定的日期获取中央银行API的汇率;

3 - ExchangeRatesProviderCacheDecorator

  • 装饰任何其他供应者类;
  • 可以使用不同的缓存策略(策略必须实现Psr\SimpleCache\CacheInterface)
  • 监控TTL并调节更新列表的过程;
<?php 

use Chetkov\Money\Exchanger\RatesProvider\CacheDecorator\ExchangeRatesProviderCacheDecorator;
use Chetkov\Money\Exchanger\RatesProvider\CacheDecorator\Strategy\ClassPropertyCacheStrategy;
use Chetkov\Money\Exchanger\RatesProvider\CbrExchangeRatesProvider;

$ratesProvider = new CbrExchangeRatesProvider();
$cacheStrategy = new ClassPropertyCacheStrategy();
$cachingDecorator = new ExchangeRatesProviderCacheDecorator($ratesProvider, $cacheStrategy, 60);

$cachingDecorator->getRates(); // Получает, кэширует и возвращает ставки от оригинального поставщика
sleep(55);
$cachingDecorator->getRates(); // Возвращает ставки из кэша
sleep(10);
$cachingDecorator->getRates(); // Получает, кэширует и возвращает ставки от оригинального поставщика

或者这样

<?php 

use Chetkov\Money\Exchanger\RatesProvider\CacheDecorator\ExchangeRatesProviderCacheDecorator;
use Chetkov\Money\Exchanger\RatesProvider\CacheDecorator\Strategy\ClassPropertyCacheStrategy;
use Chetkov\Money\Exchanger\RatesProvider\CbrExchangeRatesProvider;

$ratesProvider = new CbrExchangeRatesProvider();
$classPropertyCacheStrategy = new ClassPropertyCacheStrategy();
$redisCacheStrategy = new RedisCache();

$redisCacheDecorator = new ExchangeRatesProviderCacheDecorator($ratesProvider, $redisCacheStrategy, 3600);
$classPropertyCacheDecorator = new ExchangeRatesProviderCacheDecorator($redisCacheDecorator, $classPropertyCacheStrategy, 60);

// 1) Смотрим в кэширующем свойстве класса 
// 2) Если пусто, смотрим в редис  
// 3) Если и там пусто, идем к оригинальному провайдеру

与交易所类似,您可以创建自己的供应商实现。

PS

目前就到这里,但我认为不久的将来这个包还将看到许多改进。随着发展,我将努力保持README文件处于最新状态。

PPS

这个想法来源于马丁·福勒尔的书:“企业应用程序模板”。