v.chetkov / money
简化货币值操作的库
Requires
Requires (Dev)
- phpstan/phpstan: ^0.11.8
- phpunit/phpunit: ^7.5
- squizlabs/php_codesniffer: *
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中,这是为了理解
- 是否启用了自动货币转换
- 由哪个交换器负责
- 哪个供应者提供数据
<?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
这个想法来源于马丁·福勒尔的书:“企业应用程序模板”。