oceanmoon / quantities
Physical quantity value types with units, dimensional analysis, arithmetic and unit conversion.
Requires
- php: ^8.4
- ext-simplexml: *
- oceanmoon/core: ^2.0
Requires (Dev)
- dealerdirect/phpcodesniffer-composer-installer: ^1.0
- oceanmoon/coding-standard: ^2.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^10.0 || ^11.0 || ^12.0
- squizlabs/php_codesniffer: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
This package enables calculations and conversions with physical and non-physical quantities, including support for SI and other systems of units (including data and currencies), metric and binary prefixes, parsing, and formatting.
License | Changelog | Documentation | Examples
Description
This package provides strongly-typed classes for physical quantities (length, mass, time, temperature, etc.) and some non-physical quantities (data, money), with comprehensive unit conversion capabilities. The system automatically finds conversion factors between compatible units, supports metric and binary prefixes, handles offsets for temperature scales, and loads the latest currency exchange rates automatically.
Key capabilities include:
- Type-safe measurements: Each measurement type (Length, Mass, Time, etc.) is a separate class. Plus, you can easily create your own custom quantity type classes.
- Automatic conversion: Easily convert between any compatible units, with most common units built-in, including SI, imperial, US customary, scientific, nautical, CSS, and currencies.
- Prefix support: Full support for SI metric and binary prefixes.
- Arithmetic operations: Add, subtract, multiply, and divide quantities with automatic unit handling.
- Flexible parsing: Parse strings like
123.45 km/h,90deg, or25°Cinto Quantity objects. - String formatting: Format quantities as ASCII or Unicode, with configurable decimal places and locale-specific currency formatting.
- Part decomposition: Break measurements into components (e.g.
12° 34′ 56″or1y 3mo 2d). - Physical constants: Built-in constants like the speed of light, Planck's constant, and Avogadro's number as Quantity objects.
- Up-to-date exchange rates: Updated automatically as needed using the exchange rate API of your choice.
Development and Quality Assurance
This package was developed with Claude Code:
- The author developed the initial concept, designed the public API, and did most of the initial coding.
- Claude Code wrote the tests and most of the documentation.
- Claude Code also assisted with multiple code reviews, which led to bug fixes, performance improvements and other refinements.
The code is checked with:
- PHP_CodeSniffer, for PSR-12 compliance plus the Mossy2100 coding standard
- PHPStan, at level 9
- PHPUnit, with 100% code coverage
Requirements
- PHP ^8.4
- The
intlextension, for formatting money - The
simplexmlextension, for refreshing the currency list - mossy2100/core
Installation
composer require mossy2100/quantities
Quick start
use Mossy2100\Core\Enums\FloatFormat; use Mossy2100\Quantities\Currencies\CurrencyService; use Mossy2100\Quantities\Currencies\ExchangeRateServices\FrankfurterService; use Mossy2100\Quantities\PhysicalConstant; use Mossy2100\Quantities\QuantityType\Angle; use Mossy2100\Quantities\QuantityType\Force; use Mossy2100\Quantities\QuantityType\Frequency; use Mossy2100\Quantities\QuantityType\Length; use Mossy2100\Quantities\QuantityType\Mass; use Mossy2100\Quantities\QuantityType\Money; use Mossy2100\Quantities\QuantityType\Temperature; // Fetch exchange rates when needed: on first use, then whenever they're over an hour old CurrencyService::init(new FrankfurterService(), autoRefreshTtl: 3600); // Create measurements $distance = new Length(5, 'km'); $temp = new Temperature(25, 'degC'); $angle = new Angle(90, 'deg'); $price = new Money(4269, 'EUR'); // Convert between units $miles = $distance->to('mi'); // 3.10686... miles $fahrenheit = $temp->to('degF'); // 77°F $radians = $angle->to('rad'); // 1.5707... rad $dollars = $price->to('USD'); // e.g. 4621 USD // Convert to SI units $force = new Force(28000, 'lbf'); $siForce = $force->toSi()->autoPrefix(); // 124.55... kN $baseForce = $force->toSiBase(); // 124550.2... kg⋅m/s² // Arithmetic operations $total = $distance->add(new Length(500, 'm')); // 5.5 km $doubled = $distance->mul(2.0); // 10 km $period = new Frequency(2.4, 'GHz')->recip()->toSi()->autoPrefix(); // 416.7... ps // Physical constants $h = PhysicalConstant::planck(); $c = PhysicalConstant::speedOfLight(); // Scientific and engineering calculations $G = PhysicalConstant::gravitational(); $earthMass = new Mass(5.972e24, 'kg'); $moonMass = new Mass(7.342e22, 'kg'); $earthMoonDistance = new Length(3.844e8, 'm'); $gravity = $G->mul($earthMass)->mul($moonMass)->div($earthMoonDistance->sqr()); echo $gravity->to('N')->format(3, format: FloatFormat::Scientific), "\n"; // 1.98×10²⁰ N // Parse from strings $length = Length::parse('123.45 km'); $temp = Temperature::parse('98.6°F'); $angle = Angle::parse("45° 30' 15\""); // Format as parts $angle = new Angle(45.5042, 'deg'); echo $angle->formatParts(precision: 1); // "45° 30′ 15.1″"
Concepts
Background on the domain model and how the library represents physical measurements.
- Terminology - Key terms and definitions used throughout the library.
- Dimensions and Base Units - Dimension codes, base units, and how the library tracks physical dimensions.
- Quantity Types - Typed quantity classes like Length, Mass, and Force, and how they map to dimensions.
- Prefixes - Metric, engineering, and binary prefixes for scaling units.
- Units - Unit symbol conventions, notation rules, and supported non-ASCII and alternate symbols.
- Physical Constants - Built-in physical constants as Quantity objects.
Working with Quantities
Practical guides for using the library in your code.
- Creating Quantities - Creating new quantities with constructors and the factory method.
- Unit Conversion - Converting between units, expansion, simplification, and auto-prefixing.
- Arithmetic Operations - Add, subtract, multiply, and divide quantities.
- Calculation Examples - Real-world physics and engineering calculations.
- Currency Calculations - Example conversions and calculations involving currencies.
- Comparison Functions - Exact and approximate equality, ordering, and tolerances.
- String Functions - Parsing strings into quantities and formatting output (ASCII and Unicode).
- Part Decomposition - Working with quantities as parts (e.g. 45° 30′ 15″ or 1h 30min 45s).
- Customization - Adding custom units, conversions, and quantity type classes.
Reference
Main Public API
Other than the quantity type classes (below), these are the main classes you'll use.
| Class | Description |
|---|---|
| Quantity | Base class for all measurement types. Provides unit conversion, arithmetic operations, comparison, formatting, and part decomposition. |
| PhysicalConstant | Access to physical constants (speed of light, Planck constant, etc.) as Quantity objects. |
Quantity Types
All quantity type classes extend Quantity and define their specific units and conversions. See the
Quantity Type reference for the complete list of built-in units for each type.
| Class | Dimension | SI or common base unit | Description |
|---|---|---|---|
| Acceleration | LT-2 | m/s² | Rate of change of velocity. |
| AmountOfSubstance | N | mol | SI base quantity for counting entities. |
| Angle | A | rad | Angular measurements with trig functions. |
| Area | L2 | m² | Two-dimensional extent. |
| Capacitance | M-1L-2T4I2 | F | Ability to store electric charge. |
| CatalyticActivity | T-1N | kat | Rate of catalysis. |
| Conductance | M-1L-2T3I2 | S | Electrical conductance. |
| Data | D | B | Digital storage with metric and binary prefixes. |
| Density | ML-3 | kg/m³ | Mass per unit volume. |
| Dimensionless | empty | empty | Ratios, percentages, and pure numbers. |
| ElectricCharge | TI | C | Quantity of electricity. |
| ElectricCurrent | I | A | SI base quantity for electric current. |
| Energy | ML2T-2 | J | Capacity to do work. |
| Force | MLT-2 | N | Interaction causing acceleration. |
| Frequency | T-1 | Hz, Bq | Cycles per unit time. |
| Illuminance | L-2A2J | lx | Luminous flux per area. |
| Inductance | ML2T-2I-2 | H | Property opposing current change. |
| Length | L | m | SI base quantity for distance. |
| LuminousFlux | A2J | lm | Perceived light power. |
| LuminousIntensity | J | cd | SI base quantity for luminous intensity. |
| MagneticFlux | ML2T-2I-1 | Wb | Total magnetic field through surface. |
| MagneticFluxDensity | MT-2I-1 | T | Magnetic field strength. |
| Mass | M | kg | SI base quantity for mass. |
| Money | C | XAU | Currency conversions and calculations. |
| Power | ML2T-3 | W | Rate of energy transfer. |
| Pressure | ML-1T-2 | Pa | Force per unit area. |
| RadiationDose | L2T-2 | Gy, Sv | Absorbed and equivalent radiation dose. |
| Resistance | ML2T-3I-2 | Ω | Opposition to electric current. |
| SolidAngle | A2 | sr | Three-dimensional angular extent. |
| Temperature | H | K | SI base quantity with affine conversions. |
| Time | T | s | SI base quantity for duration. |
| Velocity | LT-1 | m/s | Rate of change of position. |
| Voltage | ML2T-3I-1 | V | Electric potential difference. |
| Volume | L3 | m³ | Three-dimensional extent. |
Services
These classes are predominantly internal, except for adding custom units via UnitService::add(), or registering new
quantity types via QuantityTypeService::add().
| Class | Description |
|---|---|
| ConversionService | Manages unit conversions and converters. |
| DimensionService | Utilities for working with physical dimension codes (validation, composition, transformation). |
| PrefixService | Manages SI and binary prefixes (lookup, filtering by group). |
| QuantityTypeService | Registry of quantity types keyed by name. |
| QuantityType | Data class for a registered quantity type: name, dimension and class. |
| UnitService | Registry of units with lookup, filtering, and loading by system. |
Units
Classes for units and conversions. You'll use these to add custom units and conversions (see Customization).
| Name | Description |
|---|---|
| Unit | Represents a single-symbol measurement unit with optional prefix support. |
| UnitTerm | A unit with optional prefix and exponent (e.g., km², ms⁻¹). |
| CompoundUnit | Compound unit expression combining unit terms via multiplication/division. |
| Prefix | SI metric and binary prefixes (kilo, mega, kibi, etc.). |
| Conversion | Represents a unit conversion with factor and error tracking. |
| UnitInterface | Interface implemented by Unit, UnitTerm, and CompoundUnit. |
Enums
| Name | Description |
|---|---|
| UnitSystem | Enum for systems of units (SI, Imperial, US Customary, etc.). |
Internal Types
These classes are used by the conversion engine and aren't part of the public API. They may change without notice.
| Name | Description |
|---|---|
| Converter | Graph-based algorithm for finding conversion paths between units. |
| FloatWithError | Floating-point numbers with tracked error bounds for precision monitoring. |
Exceptions
Custom exception types to provide additional context when needed. Both extend DomainException, as they relate to
provided values being outside a valid domain.
| Class | Description |
|---|---|
| UnknownUnitException | Thrown when a unit symbol cannot be resolved. |
| DimensionMismatchException | Thrown when units have incompatible dimensions. |
Currency Classes
Classes for currency data management and exchange rate integration.
| Class | Description |
|---|---|
| CurrencyService | Manages currency unit data and exchange rate conversions. |
| ExchangeRateServiceInterface | Contract for exchange rate providers. |
| CurrencyLayerService | CurrencyLayer API (USD-based, 1,000 req/month free). |
| ExchangeRateApiService | ExchangeRate-API (any base currency, 1,500 req/month free). |
| FixerService | Fixer.io API (EUR-based, 10,000 req/month free). |
| FrankfurterService | Frankfurter API (ECB data, completely free, no API key). |
| OpenExchangeRatesService | Open Exchange Rates API (USD-based, free tier available). |
Testing
There are two test suites:
unit(default): fast, offline tests intests/NonCurrencies.currencies: tests intests/Currenciesthat call live exchange rate APIs. They need API keys intests/Currencies/api-keys.json(seeapi-keys.json.example) and use up request quota.
# Run the unit tests vendor/bin/phpunit # Run a specific test file vendor/bin/phpunit tests/NonCurrencies/Quantity/QuantityArithmeticTest.php # Run tests matching a filter vendor/bin/phpunit --filter=testCompare # Run the live currency tests vendor/bin/phpunit --testsuite currencies # Run with coverage (generates HTML report and clover.xml): unit, currencies or all composer test all
License
MIT License - see LICENSE for details
Support
- Issues: https://github.com/mossy2100/PHP-Quantities/issues
- Documentation: See docs/ directory for detailed class documentation
For questions or suggestions, please open an issue.
Changelog
See CHANGELOG.md for version history and changes.
