定制 gosuperscript/axiom-money 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

gosuperscript/axiom-money

Composer 安装命令:

composer require gosuperscript/axiom-money

包简介

Monetary extension for Axiom - provides schema types, parsers, and operators for monetary values with strong type safety and currency validation

README 文档

README

Tests License: MIT

A monetary extension for Axiom, providing schema types, parsers, and operators for monetary values with strong type safety and currency validation.

Note: This library extends Axiom (built on gosuperscript/schema) with monetary value support.

Features

  • Schema Types: Type-safe monetary value handling with currency validation
  • Money Parser: Parse monetary values from various string formats (e.g., "EUR 100", "£50.25")
  • Operator Overloading: Mathematical operations on Money objects — addition, subtraction, and comparisons between monies, plus multiplication/division by a numeric scalar (returning an exact RationalMoney)
  • Multiple Type Variants:
    • MonetaryType: Standard monetary type with currency validation
    • MinorMonetaryType: Money from minor units (cents, pence, etc.)
    • DynamicMonetaryType: Flexible parsing that auto-detects currency
    • MonetaryIntervalType: Intervals of monetary values
  • Monetary Intervals: Support for ranges of monetary values

Requirements

  • PHP 8.4 or higher
  • ext-intl extension

Installation

Install via Composer:

composer require gosuperscript/axiom-money

Usage

Basic Money Types

use Brick\Money\Currency;
use Brick\Money\Money;
use Superscript\Axiom\Money\Types\MonetaryType;

// Create a monetary type for EUR
$eurType = new MonetaryType(Currency::of('EUR'));

// Coerce values to Money objects
$money = $eurType->coerce('100.50')->unwrap()->unwrap();
// Result: Money object with EUR 100.50

// Assert existing Money objects
$result = $eurType->assert(Money::of(50, 'EUR'));
// Result: Ok(Some(Money))

// Format money for display
$formatted = $eurType->format(Money::of(100.50, 'EUR'));
// Result: "€100.50"

Money Parser

Parse money from various string formats:

use Superscript\Axiom\Money\MoneyParser;
use Brick\Money\Money;

// Parse from "CURRENCY AMOUNT" format
$result = MoneyParser::parse('EUR 100');
$money = $result->unwrap(); // Money object: EUR 100

// Parse from currency symbol format
$result = MoneyParser::parse('£50.25');
$money = $result->unwrap(); // Money object: GBP 50.25

// Parse from "CURRENCY AMOUNT" format
$result = MoneyParser::parse('USD 1000.50');
$money = $result->unwrap(); // Money object: USD 1000.50

// Already a Money object? Just returns it
$existing = Money::of(100, 'EUR');
$result = MoneyParser::parse($existing);
$money = $result->unwrap(); // Same Money object

Minor Units

Work with minor currency units (cents, pence, etc.):

use Brick\Money\Currency;
use Superscript\Axiom\Money\Types\MinorMonetaryType;

$gbpType = new MinorMonetaryType(Currency::of('GBP'));

// Coerce from minor units (100 pence = £1.00)
$money = $gbpType->coerce(100)->unwrap()->unwrap();
// Result: Money object with GBP 1.00

// Coerce from string of minor units
$money = $gbpType->coerce('2550')->unwrap()->unwrap();
// Result: Money object with GBP 25.50

Dynamic Monetary Type

Automatically detect and parse currency from string:

use Superscript\Axiom\Money\Types\DynamicMonetaryType;

$dynamicType = new DynamicMonetaryType();

// Automatically detects currency
$money = $dynamicType->coerce('USD 100')->unwrap()->unwrap();
// Result: Money object with USD 100

$money = $dynamicType->coerce('€50.25')->unwrap()->unwrap();
// Result: Money object with EUR 50.25

Money Operations

Perform mathematical operations on Money objects:

use Brick\Money\Money;
use Superscript\Axiom\Money\Operators\MonetaryOverloader;

$overloader = new MonetaryOverloader();

$a = Money::of(100, 'EUR');
$b = Money::of(50, 'EUR');

// Addition
$sum = $overloader->evaluate($a, $b, '+');
// Result: EUR 150.00

// Subtraction
$diff = $overloader->evaluate($a, $b, '-');
// Result: EUR 50.00

// Multiplication and division require ONE numeric operand (multiplying or dividing two
// monies is dimensionally meaningless and is not supported). The numeric operand may be
// on either side for multiplication; division must be Money / number.
//
// To preserve precision, `*` and `/` return an exact Brick\Money\RationalMoney.
$product = $overloader->evaluate($a, 3, '*');        // RationalMoney, exactly 300
$product = $overloader->evaluate(3, $a, '*');        // commutative
$quotient = $overloader->evaluate($a, 3, '/');       // RationalMoney, exactly 100/3 (no rounding)

// Addition/subtraction: Money + Money stays Money; if either operand is a RationalMoney the
// result is a RationalMoney ("rational is contagious"), so chained arithmetic never rounds mid-way.
$sum = $overloader->evaluate($a, $b, '+');           // Money: EUR 150.00

// Comparisons work across Money and RationalMoney, returning bool.
$isEqual = $overloader->evaluate($a, $b, '==');     // false
$isLess = $overloader->evaluate($b, $a, '<');       // true
$isGreater = $overloader->evaluate($a, $b, '>');    // true

A RationalMoney becomes a concrete Money at the type boundary: when it lands in a MonetaryType, MinorMonetaryType, or DynamicMonetaryType field, coerce() rounds it to the currency scale — the rounding mode is configurable on the type and defaults to RoundingMode::HALF_UP, so a RationalMoney never leaves the type system. If you consume a *// result directly (outside a type), collapse it yourself:

use Brick\Math\RoundingMode;
use Brick\Money\Context\DefaultContext;

$money = $quotient->unwrap()->to(new DefaultContext(), RoundingMode::HALF_UP); // EUR 33.33

Note: MonetaryIntervalOverloader compares an interval against a Money only. A RationalMoney produced by *// cannot be compared against an interval directly — collapse it to a Money first.

Monetary Intervals

Work with ranges of monetary values:

use Brick\Money\Currency;
use Brick\Money\Money;
use Superscript\Axiom\Money\Types\MonetaryIntervalType;
use Superscript\MonetaryInterval\MonetaryInterval;
use Superscript\MonetaryInterval\IntervalNotation;

$intervalType = new MonetaryIntervalType(Currency::of('EUR'));

// Parse interval from string notation
$interval = $intervalType->coerce('[100,200]')->unwrap()->unwrap();
// Result: MonetaryInterval from EUR 100 to EUR 200 (inclusive)

// Create MonetaryInterval directly
$interval = new MonetaryInterval(
    left: Money::of(100, 'EUR'),
    right: Money::of(200, 'EUR'),
    notation: IntervalNotation::CLOSED
);

// Format interval
$formatted = $intervalType->format($interval);
// Result: "[EUR 100.00, EUR 200.00]"

Monetary Interval Operations

use Superscript\Axiom\Money\Operators\MonetaryIntervalOverloader;

$overloader = new MonetaryIntervalOverloader();

$interval1 = new MonetaryInterval(
    left: Money::of(100, 'EUR'),
    right: Money::of(200, 'EUR'),
    notation: IntervalNotation::CLOSED
);

$interval2 = new MonetaryInterval(
    left: Money::of(150, 'EUR'),
    right: Money::of(250, 'EUR'),
    notation: IntervalNotation::CLOSED
);

// Check if intervals overlap
$overlaps = $overloader->evaluate($interval1, $interval2, '&&');
// Result: true (they overlap from EUR 150 to EUR 200)

// Union of intervals
$union = $overloader->evaluate($interval1, $interval2, '||');
// Result: MonetaryInterval from EUR 100 to EUR 250

Development

Running Tests

# Run all tests
composer test

# Run unit tests only
composer test:unit

# Run type checking
composer test:types

# Run mutation testing
composer test:infection

Code Quality

The project enforces 100% code coverage and uses:

  • PHPUnit: Unit testing
  • PHPStan: Static analysis
  • Laravel Pint: Code style
  • Infection: Mutation testing

Linting

vendor/bin/pint

Dependencies

This library builds on several excellent packages:

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate and maintain the existing code quality standards.

gosuperscript/axiom-money 适用场景与选型建议

gosuperscript/axiom-money 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 21.23k 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 01 月 26 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「schema」 「monetary」 「validation」 「money」 「currency」 「interval」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 gosuperscript/axiom-money 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 gosuperscript/axiom-money 我们能提供哪些服务?
定制开发 / 二次开发

基于 gosuperscript/axiom-money 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 21.23k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 41
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-01-26