andanteproject / measurement
Modern, type-safe PHP library for handling physical measurements with automatic unit conversion and internationalization
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 2
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/andanteproject/measurement
Requires
- php: ^8.1
Requires (Dev)
- brick/math: ^0.11
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^10.1
Suggests
- ext-bcmath: Alternative to GMP for speeding up brick/math calculations
- ext-gmp: Significantly speeds up brick/math calculations (recommended with brick/math)
- ext-intl: Required for locale-aware number formatting
- brick/math: For precise arbitrary-precision decimal arithmetic (recommended). Install GMP or BCMath extension for better performance.
README
Measurement
PHP Library - AndanteProject
A modern, type-safe PHP library for handling physical measurements with automatic unit conversion, internationalization, and precise calculations.
Table of Contents
- Features
- Installation
- Quick Start
- Core Concepts
- Working with Quantities
- Parsing and Formatting
- Available Quantities
- Length, Mass, Time, Temperature, Electric Current
- Area, Volume, Velocity, Acceleration
- Force, Pressure, Energy, Power, Density
- Frequency, Angle
- Electric Potential, Electric Resistance, Electric Capacitance, Electric Charge
- Inductance, Magnetic Flux
- Luminous Intensity, Luminous Flux, Illuminance
- Calorific Value, Digital Information, Data Transfer Rate
- Registries
- Adding Custom Quantities
- Testing
Features
- Type-Safe Quantities - Three levels of type safety (dimension, system, unit) with compile-time type checking and full IDE autocompletion
- Dimensional Analysis - Automatic type resolution (
Length × Length = Area,Length ÷ Time = Velocity) that prevents dimensional errors at compile time - Arbitrary Precision - Exact calculations using
brick/mathwith no floating-point precision errors, handles very large and very small numbers accurately - Auto-Scaling - Smart unit selection (
1000 g→1 kg) that automatically chooses the most appropriate unit representation across all quantity types - String Parsing - Parse strings like
"100 km","5.5 kWh","25 °C"with locale-aware number parsing, supports unit symbols and full unit names - Flexible Formatting - Multiple output styles (Short, Long, Narrow, Value-only, Unit-only) with locale-aware number formatting and translated unit names
- Internationalization - 9 locales (en, de, es, fr, it, pt, ja, ru, zh) with separate locale support for numbers and unit names
- Locale-Aware Numbers - Parse
"1.500,5 m"(IT) or"1,500.5 m"(US) with custom thousand and decimal separators - Unit Systems - Complete SI & Metric support, full Imperial unit support with conversions, and Digital units with both SI (decimal) and IEC (binary) prefixes
- Extensible - Easy to add custom dimensions and units with provider-based registration system and full integration with existing library features
- Modern PHP 8.1+ - Enums, readonly properties, strict types, PHPStan level 9, immutable value objects, trait-based functionality composition
Installation
composer require andanteproject/measurement
Requirements
- PHP 8.1 or higher
brick/math(for arbitrary precision arithmetic)
Quick Start
use Andante\Measurement\Math\NumberFactory; use Andante\Measurement\Quantity\Length\Metric\Meter; use Andante\Measurement\Quantity\Length\Metric\Kilometer; use Andante\Measurement\Quantity\Energy\Electric\KilowattHour; use Andante\Measurement\Quantity\Volume\Metric\CubicMeter; use Andante\Measurement\Unit\Length\MetricLengthUnit; use Andante\Measurement\Unit\Energy\SIEnergyUnit; use Andante\Measurement\Parser\Parser; use Andante\Measurement\Parser\ParseOptions; use Andante\Measurement\Formatter\Formatter; use Andante\Measurement\Formatter\FormatOptions; use Andante\Measurement\Formatter\FormatStyle; use Andante\Measurement\Unit\SymbolNotation; // Create quantities using unit-specific classes $distance = Meter::of(NumberFactory::create('5000')); $energy = KilowattHour::of(NumberFactory::create('150')); // Convert to different units $inKilometers = $distance->to(MetricLengthUnit::Kilometer); // 5 km $inJoules = $energy->to(SIEnergyUnit::Joule); // 540,000,000 J // Arithmetic operations $doubled = $distance->multiplyBy(NumberFactory::create('2')); // 10000 m $sum = $distance->add(Kilometer::of(NumberFactory::create('2'))); // 7000 m $diff = $distance->subtract(Kilometer::of(NumberFactory::create('1'))); // 4000 m $half = $distance->divideBy(NumberFactory::create('2')); // 2500 m // Type-safe: incompatible types won't compile // $distance->add($energy); // ❌ Type error! // Auto-scale to the most readable unit $largeDistance = Meter::of(NumberFactory::create('5000')); $scaled = $largeDistance->autoScale(); // 5 km // Parse from strings with options $parser = Parser::global(); // Simple parsing (no options) $parsed = $parser->parse('100 km'); // Parse with Italian locale (for number formatting) $parsed = $parser->parse( '1.234,56 m', ParseOptions::fromLocale('it_IT') ); // Italian: 1234.56 m // Parse with Italian locale (different number) $parsed = $parser->parse( '1.500,5 km', ParseOptions::fromLocale('it_IT') ); // Italian: 1500.5 km // Parse with default unit (for numbers without units) $parsed = $parser->parse( '100', ParseOptions::create() ->withDefaultUnit(MetricLengthUnit::Meter) ); // 100 m // Parse with custom thousand separator $parsed = $parser->parse( '1 234.56 m', ParseOptions::create() ->withThousandSeparator(' ') ->withDecimalSeparator('.') ); // 1234.56 m // Parse with custom decimal separator $parsed = $parser->parse( '1234,56 m', ParseOptions::create() ->withDecimalSeparator(',') ); // 1234.56 m // Parse with locale and default unit $parsed = $parser->parse( '1.500', ParseOptions::fromLocale('it_IT') ->withDefaultUnit(MetricLengthUnit::Kilometer) ); // 1500 km // Parse with all custom separators $parsed = $parser->parse( '1_234|56 m', ParseOptions::create() ->withThousandSeparator('_') ->withDecimalSeparator('|') ); // 1234.56 m // Format with options $formatter = Formatter::global(); // Default formatting (short style with symbol) echo $formatter->format($distance); // "5,000 m" // Format with Italian locale echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ); // "5.000 m" // Format with long style (translated unit names) echo $formatter->format( $distance, FormatOptions::create() ->withStyle(FormatStyle::Long) ); // "5,000 meters" // Format with long style and Italian locale echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withStyle(FormatStyle::Long) ); // "5.000 metri" // Format with narrow style (no space) echo $formatter->format( $distance, FormatOptions::create() ->withStyle(FormatStyle::Narrow) ); // "5,000m" // Format with narrow style and Italian locale echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withStyle(FormatStyle::Narrow) ); // "5.000m" // Format with value only (no unit) echo $formatter->format( $distance, FormatOptions::create() ->withStyle(FormatStyle::ValueOnly) ); // "5,000" // Format with unit symbol only echo $formatter->format( $distance, FormatOptions::create() ->withStyle(FormatStyle::UnitSymbolOnly) ); // "m" // Format with unit name only echo $formatter->format( $distance, FormatOptions::create() ->withStyle(FormatStyle::UnitNameOnly) ); // "meters" // Format with unit name only and Italian locale echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withStyle(FormatStyle::UnitNameOnly) ); // "metri" // Format with fixed precision echo $formatter->format( $distance, FormatOptions::create() ->withPrecision(2) ); // "5,000.00 m" // Format with precision and Italian locale echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withPrecision(2) ); // "5.000,00 m" // Format with precision and long style echo $formatter->format( $distance, FormatOptions::create() ->withPrecision(3) ->withStyle(FormatStyle::Long) ); // "5,000.000 meters" // Format with custom thousand separator echo $formatter->format( $distance, FormatOptions::create() ->withThousandSeparator(' ') ); // "5 000 m" // Format with custom decimal separator $smallDistance = Meter::of(NumberFactory::create('1234.56')); echo $formatter->format( $smallDistance, FormatOptions::create() ->withDecimalSeparator(',') ); // "1,234,56 m" // Format with custom separators echo $formatter->format( $smallDistance, FormatOptions::create() ->withThousandSeparator('_') ->withDecimalSeparator('|') ); // "1_234|56 m" // Format with separate unit locale (Italian numbers, English units) echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withUnitLocale('en_US') ->withStyle(FormatStyle::Long) ); // "5.000 meters" (Italian numbers, English unit name) // Format with IEEE symbol notation $energy = KilowattHour::of(NumberFactory::create('150')); echo $formatter->format( $energy, FormatOptions::create() ->withSymbolNotation(SymbolNotation::IEEE) ); // "150 kW·h" // Format with ASCII symbol notation echo $formatter->format( $energy, FormatOptions::create() ->withSymbolNotation(SymbolNotation::ASCII) ); // "150 kW*h" // Format with Unicode symbol notation $volume = CubicMeter::of(NumberFactory::create('1000000')); echo $formatter->format( $volume, FormatOptions::create() ->withSymbolNotation(SymbolNotation::Unicode) ); // "1,000,000 m³" // Format with multiple options combined echo $formatter->format( $smallDistance, FormatOptions::fromLocale('it_IT') ->withStyle(FormatStyle::Long) ->withPrecision(2) ); // "1.234,56 metri" // Format with all options echo $formatter->format( $distance, FormatOptions::fromLocale('it_IT') ->withUnitLocale('en_US') ->withStyle(FormatStyle::Long) ->withPrecision(3) ->withSymbolNotation(SymbolNotation::Unicode) ); // "5.000,000 meters"
Core Concepts
Dimension vs Unit vs Quantity
- Dimension: The physical nature (Length, Mass, Energy)
- Unit: A specific scale (meter, kilometer, foot)
- Quantity: A value + unit (5 meters)
Three Levels of Type Safety
The library provides three levels of specificity for type-hinting quantities. This allows you to be as strict or flexible as your use case requires - from accepting any length unit, to requiring a specific measurement system, to enforcing an exact unit.
use Andante\Measurement\Quantity\Length\Length; use Andante\Measurement\Quantity\Length\MetricLength; use Andante\Measurement\Quantity\Length\Metric\Meter; use Andante\Measurement\Unit\Length\MetricLengthUnit; // Level 1: Generic - accepts any length unit (meters, feet, miles, etc.) function calculateArea(Length $width, Length $height): Area { return $width->multiply($height); } // Level 2: System-specific - only metric units allowed (meters, kilometers, etc.) function europeanDistance(MetricLength $distance): void { // Rejects imperial units like feet or miles at compile time } // Level 3: Unit-specific - only meters, nothing else function precisionMeasurement(Meter $length): void { // Even kilometers or centimeters are rejected }
Creating Quantities
There are multiple ways to create quantities, each corresponding to the three levels of type safety. Use NumberFactory::create() to create precise numeric values from strings, integers, or floats.
use Andante\Measurement\Math\NumberFactory; use Andante\Measurement\Quantity\Length\Length; use Andante\Measurement\Quantity\Length\MetricLength; use Andante\Measurement\Quantity\Length\Metric\Meter; use Andante\Measurement\Unit\Length\MetricLengthUnit; use Andante\Measurement\Unit\Length\ImperialLengthUnit; // Unit-specific class - most type-safe $meter = Meter::of(NumberFactory::create('100')); // Mid-level class with unit - system-constrained $length = MetricLength::of( NumberFactory::create('100'), MetricLengthUnit::Kilometer ); // Generic class with any unit - most flexible $imperial = Length::of( NumberFactory::create('5280'), ImperialLengthUnit::Foot );
Working with Quantities
Once you have quantity objects, you can convert between units, perform arithmetic, compare values, and more. All operations are immutable - they return new quantity objects rather than modifying the original.
Conversions
Use the to() method to convert a quantity to a different unit within the same dimension. The conversion is handled automatically using the library's conversion factor registry.
use Andante\Measurement\Unit\Length\MetricLengthUnit; use Andante\Measurement\Unit\Length\ImperialLengthUnit; $meters = Meter::of(NumberFactory::create('1000')); // Convert to another unit in the same dimension $kilometers = $meters->to(MetricLengthUnit::Kilometer); // 1 km $feet = $meters->to(ImperialLengthUnit::Foot); // 3280.84 ft // Get the numeric value echo $kilometers->getValue()->value(); // "1" echo $kilometers->getUnit()->symbol(); // "km"
Arithmetic
Quantities support addition, subtraction, multiplication by scalars, and division by scalars. When adding or subtracting quantities with different units, the right operand is automatically converted to the left operand's unit.
$a = Meter::of(NumberFactory::create('100')); $b = Meter::of(NumberFactory::create('50')); // Same-unit arithmetic $sum = $a->add($b); // 150 m $diff = $a->subtract($b); // 50 m $scaled = $a->multiplyBy(NumberFactory::create('2')); // 200 m $half = $a->divideBy(NumberFactory::create('2')); // 50 m // Cross-unit arithmetic (auto-converts to left operand's unit) $km = Kilometer::of(NumberFactory::create('1')); $result = $km->add($a); // 1.1 km (100m converted to 0.1km)
Dimensional Analysis
When multiplying or dividing quantities, the library automatically determines the result type:
use Andante\Measurement\Quantity\Length\Metric\Meter; use Andante\Measurement\Quantity\Time\SI\Second; use Andante\Measurement\Quantity\Mass\Metric\Kilogram; // Length × Length = Area $width = Meter::of(NumberFactory::create('5')); $height = Meter::of(NumberFactory::create('3')); $area = $width->multiply($height); // SquareMeter (15 m²) // Length ÷ Time = Velocity $distance = Meter::of(NumberFactory::create('100')); $time = Second::of(NumberFactory::create('10')); $velocity = $distance->divide($time); // MeterPerSecond (10 m/s) // Mass × Acceleration = Force $mass = Kilogram::of(NumberFactory::create('10')); $accel = MeterPerSecondSquared::of(NumberFactory::create('9.8')); $force = $mass->multiply($accel); // Newton (98 N)
Comparisons
Compare quantities using intuitive methods. Comparisons work across different units - the library automatically converts to a common unit before comparing.
$a = Meter::of(NumberFactory::create('100')); $b = Meter::of(NumberFactory::create('50')); $a->isGreaterThan($b); // true $a->isLessThan($b); // false $a->equals($b); // false $a->isGreaterOrEqual($b); // true // Cross-unit comparisons work too $km = Kilometer::of(NumberFactory::create('1')); $a->isLessThan($km); // true (100m < 1000m)
Auto-Scaling
The autoScale() method automatically converts a quantity to the most human-readable unit. It prefers values between 1 and 1000, choosing larger or smaller units as appropriate.
// Automatically choose the most readable unit $grams = Gram::of(NumberFactory::create('5000')); $scaled = $grams->autoScale(); // Kilogram (5 kg) $bytes = Byte::of(NumberFactory::create('1048576')); $scaled = $bytes->autoScale(); // Megabyte (1 MB) // Works with all quantity types $watts = Watt::of(NumberFactory::create('1500000')); $scaled = $watts->autoScale(); // Megawatt (1.5 MW)
Parsing and Formatting
The library includes powerful parsing and formatting capabilities with full internationalization support. Parse measurement strings from user input, and format quantities for display in any locale.
Parsing Strings
Convert strings like "100 km" or "5.5 kWh" into quantity objects. The parser handles unit symbols, full unit names, and locale-specific number formats.
use Andante\Measurement\Parser\Parser; use Andante\Measurement\Parser\ParseOptions; $parser = Parser::global(); // Simple parsing $length = $parser->parse('100 km'); $energy = $parser->parse('5.5 kWh'); $temp = $parser->parse('25 °C'); // With locale (for number formatting) $options = ParseOptions::fromLocale('it_IT'); $length = $parser->parse('1.234,56 m', $options); // Italian: 1234.56 m $options = ParseOptions::fromLocale('en_US'); $length = $parser->parse('1,234.56 m', $options); // US: 1234.56 m // With default unit (for numbers without units) $options = ParseOptions::create()->withDefaultUnit(MetricLengthUnit::Meter); $length = $parser->parse('100', $options); // 100 m // Safe parsing (returns null on failure) $result = $parser->tryParse('invalid'); // null
ParseOptions Reference
| Option | Method | Default | Description |
|---|---|---|---|
| locale | fromLocale($locale) / withLocale($locale) |
null |
Locale for number formatting (e.g., 'it_IT', 'de_DE'). Determines thousand/decimal separators via ICU. |
| thousandSeparator | withThousandSeparator($sep) |
',' |
Character used as thousand separator. Overrides locale setting. |
| decimalSeparator | withDecimalSeparator($sep) |
'.' |
Character used as decimal separator. Overrides locale setting. |
| defaultUnit | withDefaultUnit($unit) |
null |
Unit to assume when parsing numbers without unit symbols (e.g., '100' → 100 m). |
Formatting Output
Format quantities for display with control over style, precision, and locale. The formatter supports multiple styles (Short, Long, Narrow) and translates unit names into 9 languages.
use Andante\Measurement\Formatter\Formatter; use Andante\Measurement\Formatter\FormatOptions; use Andante\Measurement\Formatter\FormatStyle; $formatter = Formatter::global(); $length = Meter::of(NumberFactory::create('1500')); // Default (short style with symbol) echo $formatter->format($length); // "1,500 m" // Long style with unit name $options = FormatOptions::create()->withStyle(FormatStyle::Long); echo $formatter->format($length, $options); // "1,500 meters" // With locale $options = FormatOptions::fromLocale('de_DE'); echo $formatter->format($length, $options); // "1.500 m" // Long style with locale (translated unit names) $options = FormatOptions::fromLocale('it_IT')->withStyle(FormatStyle::Long); echo $formatter->format($length, $options); // "1.500 metri" // Fixed precision $options = FormatOptions::create()->withPrecision(2); echo $formatter->format($length, $options); // "1,500.00 m" // Narrow style (no space between number and unit) $options = FormatOptions::create()->withStyle(FormatStyle::Narrow); echo $formatter->format($length, $options); // "1,500m"
FormatOptions Reference
| Option | Method | Default | Description |
|---|---|---|---|
| locale | fromLocale($locale) / withLocale($locale) |
null |
Locale for number formatting (thousand/decimal separators). |
| unitLocale | withUnitLocale($locale) |
same as locale |
Separate locale for unit name translations. Allows Italian numbers with English unit names. |
| precision | withPrecision($int) |
null (auto) |
Number of decimal places. null preserves input precision and removes trailing zeros. |
| thousandSeparator | withThousandSeparator($sep) |
',' |
Character used as thousand separator. Overrides locale setting. |
| decimalSeparator | withDecimalSeparator($sep) |
'.' |
Character used as decimal separator. Overrides locale setting. |
| style | withStyle($style) |
FormatStyle::Short |
Output style (see FormatStyle table below). |
| notation | withSymbolNotation($notation) |
SymbolNotation::Default |
Symbol notation style (see SymbolNotation table below). |
FormatStyle Options
| Style | Example | Description |
|---|---|---|
FormatStyle::Short |
"1,500 m" |
Unit symbol with space (default). |
FormatStyle::Long |
"1,500 meters" |
Full unit name, translated if available. |
FormatStyle::Narrow |
"1,500m" |
Unit symbol without space. |
FormatStyle::ValueOnly |
"1,500" |
Numeric value only, no unit. Useful for charts and data export. |
FormatStyle::UnitSymbolOnly |
"m" |
Unit symbol only, no value. Useful for table headers. |
FormatStyle::UnitNameOnly |
"meters" |
Full unit name only, no value. Useful for legends. |
SymbolNotation Options
| Notation | Example | Description |
|---|---|---|
SymbolNotation::Default |
"Gbps", "kWh", "m³" |
Most common/recognizable form. |
SymbolNotation::IEEE |
"Gbit/s", "kW·h" |
Technical/standards-compliant form. |
SymbolNotation::ASCII |
"m3", "um", "kW*h" |
Keyboard-friendly, no special characters. |
SymbolNotation::Unicode |
"m³", "μm", "kW·h" |
Proper Unicode symbols. |
Registries
The library uses four registries to manage units, conversions, and dimensional analysis. All registries are pre-configured with built-in quantities.
UnitRegistry
Maps units to their quantity classes. Used for parsing and creating quantities.
use Andante\Measurement\Registry\UnitRegistry; $registry = UnitRegistry::global(); // Find a unit by symbol $unit = $registry->findBySymbol('km'); // MetricLengthUnit::Kilometer // Get the quantity class for a unit $class = $registry->getQuantityClass(MetricLengthUnit::Meter); // Meter::class // Get all units for a dimension $lengthUnits = $registry->getUnitsForDimension(Length::instance()); // Get only metric units $metricUnits = $registry->getMetricUnits(Length::instance());
ConversionFactorRegistry
Stores conversion factors from each unit to its dimension's base unit.
use Andante\Measurement\Registry\ConversionFactorRegistry; $registry = ConversionFactorRegistry::global(); // Get conversion rule for a unit $rule = $registry->get(MetricLengthUnit::Kilometer); // factor: 1000 (1 km = 1000 m) // Temperature uses affine conversions (factor + offset) $rule = $registry->get(TemperatureUnit::Celsius); // factor: 1, offset: 273.15 (K = °C + 273.15)
ResultQuantityRegistry
Determines what quantity class to return from dimensional operations.
use Andante\Measurement\Registry\ResultQuantityRegistry; $registry = ResultQuantityRegistry::global(); // What class should Meter × Meter return? $resultClass = $registry->getResultClass( Meter::class, new DimensionalFormula(length: 2) // L² ); // Returns: MetricArea::class (preserves metric system)
FormulaUnitRegistry
Maps dimensional formulas to default units for each system. When the library creates a result from dimensional analysis, it uses this registry to determine which unit to express the result in.
use Andante\Measurement\Registry\FormulaUnitRegistry; $registry = FormulaUnitRegistry::global(); // Default unit for velocity (L¹T⁻¹) $unit = $registry->getDefaultUnit(new DimensionalFormula(length: 1, time: -1)); // Returns: MetricVelocityUnit::MeterPerSecond // Imperial default $unit = $registry->getDefaultUnit( new DimensionalFormula(length: 1, time: -1), UnitSystem::Imperial ); // Returns: ImperialVelocityUnit::FootPerSecond
QuantityDefaultConfigProviderInterface
The QuantityDefaultConfigProviderInterface is the recommended way to register custom quantities with all four registries at once. Instead of manually registering with each registry, implement this interface to centralize your quantity's configuration.
use Andante\Measurement\Contract\Registry\QuantityDefaultConfigProviderInterface; use Andante\Measurement\Registry\UnitRegistry; use Andante\Measurement\Registry\ConversionFactorRegistry; use Andante\Measurement\Registry\ResultQuantityRegistry; use Andante\Measurement\Registry\FormulaUnitRegistry; final class MyQuantityProvider implements QuantityDefaultConfigProviderInterface { public function registerUnits(UnitRegistry $registry): void { // Register unit → quantity class mappings } public function registerConversionFactors(ConversionFactorRegistry $registry): void { // Register unit → base unit conversion factors } public function registerResultMappings(ResultQuantityRegistry $registry): void { // Register dimensional formula → result class mappings } public function registerFormulaUnits(FormulaUnitRegistry $registry): void { // Register dimensional formula → default unit mappings } } // Register with all registries at once $provider = MyQuantityProvider::global(); $provider->registerUnits(UnitRegistry::global()); $provider->registerConversionFactors(ConversionFactorRegistry::global()); $provider->registerResultMappings(ResultQuantityRegistry::global()); $provider->registerFormulaUnits(FormulaUnitRegistry::global());
Adding Custom Quantities
The library is fully extensible - you can add your own quantity types that integrate seamlessly with the existing system. This section walks through creating a custom "Viscosity" quantity as an example. The same pattern applies to any physical quantity you need to add.
Step 1: Create the Dimension
A dimension represents the physical nature of a quantity, defined by its dimensional formula using the seven SI base dimensions: Length (L), Mass (M), Time (T), Electric Current (I), Temperature (Θ), Amount of Substance (N), and Luminous Intensity (J).
Examples of dimensional formulas:
- Velocity = L¹T⁻¹ (length per time)
- Force = L¹M¹T⁻² (mass times acceleration)
- Pressure = L⁻¹M¹T⁻² (force per area)
- Viscosity = L⁻¹M¹T⁻¹ (used in this example)
use Andante\Measurement\Contract\DimensionInterface; use Andante\Measurement\Dimension\DimensionalFormula; final class Viscosity implements DimensionInterface { private static ?self $instance = null; private static ?DimensionalFormula $formula = null; private function __construct() {} public static function instance(): self { return self::$instance ??= new self(); } public function getFormula(): DimensionalFormula { // Dynamic viscosity: M¹L⁻¹T⁻¹ (kg/(m·s)) return self::$formula ??= new DimensionalFormula( mass: 1, length: -1, time: -1 ); } }
Step 2: Create the Unit Enum
Units are implemented as PHP enums that implement UnitInterface. Each unit defines its symbol, name, dimension, and measurement system (SI, Metric, or Imperial). The enum pattern provides type safety and IDE autocompletion.
use Andante\Measurement\Contract\UnitInterface; use Andante\Measurement\Unit\UnitSystem; use Andante\Measurement\Unit\SymbolNotation; enum ViscosityUnit: string implements UnitInterface { case PascalSecond = 'Pa·s'; case Poise = 'P'; case Centipoise = 'cP'; public function symbol(SymbolNotation $notation = SymbolNotation::Default): string { return match ($notation) { SymbolNotation::ASCII => match ($this) { self::PascalSecond => 'Pa*s', self::Poise => 'P', self::Centipoise => 'cP', }, default => $this->value, }; } public function name(): string { return match ($this) { self::PascalSecond => 'Pascal second', self::Poise => 'Poise', self::Centipoise => 'Centipoise', }; } public function dimension(): DimensionInterface { return Viscosity::instance(); } public function system(): UnitSystem { return UnitSystem::SI; } }
Step 3: Create the Quantity Interface
Create an interface that extends QuantityInterface. This enables type-hinting for your quantity in function signatures and allows for the three-level type safety pattern (generic → system-specific → unit-specific).
use Andante\Measurement\Contract\QuantityInterface; interface ViscosityInterface extends QuantityInterface { }
Step 4: Create Quantity Classes
Create the actual quantity classes that hold values. Use the provided traits (ConvertibleTrait, ComparableTrait, CalculableTrait, AutoScalableTrait) to get conversion, comparison, arithmetic, and auto-scaling functionality without writing boilerplate code.
use Andante\Measurement\Contract\Math\NumberInterface; use Andante\Measurement\Contract\UnitInterface; use Andante\Measurement\Contract\QuantityFactoryInterface; use Andante\Measurement\Contract\ConvertibleInterface; use Andante\Measurement\Contract\ComparableInterface; use Andante\Measurement\Contract\CalculableInterface; use Andante\Measurement\Quantity\Trait\ConvertibleTrait; use Andante\Measurement\Quantity\Trait\ComparableTrait; use Andante\Measurement\Quantity\Trait\CalculableTrait; use Andante\Measurement\Exception\InvalidUnitException; // Unit-specific class final class PascalSecond implements ViscosityInterface, QuantityFactoryInterface, ConvertibleInterface, ComparableInterface, CalculableInterface { use ConvertibleTrait; use ComparableTrait; use CalculableTrait; private function __construct( private readonly NumberInterface $value, private readonly UnitInterface $unit, ) {} public static function of(NumberInterface $value): self { return new self($value, ViscosityUnit::PascalSecond); } public static function from(NumberInterface $value, UnitInterface $unit): self { if (ViscosityUnit::PascalSecond !== $unit) { throw InvalidUnitException::forInvalidUnit($unit, ViscosityUnit::PascalSecond, self::class); } return new self($value, $unit); } public function getValue(): NumberInterface { return $this->value; } public function getUnit(): UnitInterface { return $this->unit; } }
Step 5: Create a Provider
The provider centralizes all registry configuration for your quantity. It defines which units exist, their conversion factors to the base unit, and how dimensional analysis results should be mapped. This is the recommended pattern used by all built-in quantities.
use Andante\Measurement\Contract\Registry\QuantityDefaultConfigProviderInterface; use Andante\Measurement\Converter\ConversionRule; use Andante\Measurement\Math\NumberFactory; final class ViscosityProvider implements QuantityDefaultConfigProviderInterface { private static ?self $instance = null; private function __construct() {} public static function global(): self { return self::$instance ??= new self(); } private function getUnits(): array { return [ [ViscosityUnit::PascalSecond, PascalSecond::class, '1'], [ViscosityUnit::Poise, Poise::class, '0.1'], [ViscosityUnit::Centipoise, Centipoise::class, '0.001'], ]; } public function registerUnits(UnitRegistry $registry): void { foreach ($this->getUnits() as [$unit, $quantityClass, $factor]) { $registry->register($unit, $quantityClass); } } public function registerConversionFactors(ConversionFactorRegistry $registry): void { foreach ($this->getUnits() as [$unit, $quantityClass, $factor]) { $registry->register($unit, ConversionRule::factor(NumberFactory::create($factor))); } } public function registerResultMappings(ResultQuantityRegistry $registry): void { $formula = Viscosity::instance()->getFormula(); foreach ($this->getUnits() as [$unit, $quantityClass, $factor]) { $registry->register($quantityClass, $formula, DynamicViscosity::class); } $registry->registerGeneric($formula, DynamicViscosity::class); } public function registerFormulaUnits(FormulaUnitRegistry $registry): void { $registry->register( Viscosity::instance()->getFormula(), ViscosityUnit::PascalSecond ); } }
Step 6: Register with the Library
Call your provider's registration methods during application bootstrap to make your quantity available throughout the library. After registration, parsing, formatting, conversions, and dimensional analysis will all work with your custom quantity.
// In your application bootstrap ViscosityProvider::global()->registerUnits(UnitRegistry::global()); ViscosityProvider::global()->registerConversionFactors(ConversionFactorRegistry::global()); ViscosityProvider::global()->registerResultMappings(ResultQuantityRegistry::global()); ViscosityProvider::global()->registerFormulaUnits(FormulaUnitRegistry::global()); // Now you can use your custom quantity! $viscosity = PascalSecond::of(NumberFactory::create('0.001')); $inCentipoise = $viscosity->to(ViscosityUnit::Centipoise); // 1 cP
Step 7: Add Translations (Optional)
To enable localized formatting with FormatStyle::Long, register translations programmatically using the TranslationLoader::registerTranslation() method.
use Andante\Measurement\Translation\TranslationLoader; // Get or create a translation loader for your locale $loader = new TranslationLoader('en'); // Register translations for your custom units $loader->registerTranslation(ViscosityUnit::PascalSecond, [ 'one' => 'pascal second', 'other' => 'pascal seconds', ]); $loader->registerTranslation(ViscosityUnit::Poise, [ 'one' => 'poise', 'other' => 'poise', ]); $loader->registerTranslation(ViscosityUnit::Centipoise, [ 'one' => 'centipoise', 'other' => 'centipoise', ]); // Use the loader with the formatter $formatter = new Formatter($loader);
The registerTranslation() method accepts a unit and an array mapping plural rules (one, other) to translated names. Registered translations take precedence over built-in translations, so you can also use this to override existing unit names if needed.
Available Quantities
The library provides 29 quantity types with 200+ units. Each quantity includes:
- A generic class accepting any unit in the dimension
- Mid-level classes for system-specific type safety (Metric/Imperial/SI)
- Unit-specific classes for maximum type safety
Length [L¹]
The SI base unit of distance. Supports metric and imperial systems.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Length |
any | - |
| System-specific | MetricLength |
any metric (MetricLengthUnit) |
- |
| System-specific | ImperialLength |
any imperial (ImperialLengthUnit) |
- |
| Unit-specific | Meter |
Meter |
m |
| Unit-specific | Kilometer |
Kilometer |
km |
| Unit-specific | Hectometer |
Hectometer |
hm |
| Unit-specific | Decameter |
Decameter |
dam |
| Unit-specific | Decimeter |
Decimeter |
dm |
| Unit-specific | Centimeter |
Centimeter |
cm |
| Unit-specific | Millimeter |
Millimeter |
mm |
| Unit-specific | Micrometer |
Micrometer |
μm |
| Unit-specific | Nanometer |
Nanometer |
nm |
| Unit-specific | Foot |
Foot |
ft |
| Unit-specific | Inch |
Inch |
in |
| Unit-specific | Yard |
Yard |
yd |
| Unit-specific | Mile |
Mile |
mi |
| Unit-specific | NauticalMile |
NauticalMile |
nmi |
Mass [M¹]
The SI base unit of mass. Supports metric and imperial systems.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Mass |
any | - |
| System-specific | MetricMass |
any metric (MetricMassUnit) |
- |
| System-specific | ImperialMass |
any imperial (ImperialMassUnit) |
- |
| Unit-specific | Kilogram |
Kilogram |
kg |
| Unit-specific | Gram |
Gram |
g |
| Unit-specific | Milligram |
Milligram |
mg |
| Unit-specific | Microgram |
Microgram |
μg |
| Unit-specific | Tonne |
Tonne |
t |
| Unit-specific | Hectogram |
Hectogram |
hg |
| Unit-specific | Decagram |
Decagram |
dag |
| Unit-specific | Decigram |
Decigram |
dg |
| Unit-specific | Centigram |
Centigram |
cg |
| Unit-specific | Pound |
Pound |
lb |
| Unit-specific | Ounce |
Ounce |
oz |
| Unit-specific | Stone |
Stone |
st |
| Unit-specific | ShortTon |
ShortTon |
ton |
| Unit-specific | LongTon |
LongTon |
long ton |
Time [T¹]
The SI base unit of time. All Time classes include PHP DateInterval integration:
toPhpDateInterval()- convert to PHP\DateIntervalofPhpDateInterval(\DateInterval $interval)- create from PHP\DateInterval
// Convert to DateInterval $hours = Hour::of(NumberFactory::create('2.5')); $interval = $hours->toPhpDateInterval(); // PT2H30M // Create from DateInterval $interval = new \DateInterval('PT1H30M45S'); $seconds = Second::ofPhpDateInterval($interval); // $seconds->getValue()->value() = '5445'
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Time |
any (TimeUnit) |
- |
| Unit-specific | Second |
Second |
s |
| Unit-specific | Millisecond |
Millisecond |
ms |
| Unit-specific | Microsecond |
Microsecond |
μs |
| Unit-specific | Nanosecond |
Nanosecond |
ns |
| Unit-specific | Minute |
Minute |
min |
| Unit-specific | Hour |
Hour |
h |
| Unit-specific | Day |
Day |
d |
| Unit-specific | Week |
Week |
wk |
Temperature [Θ¹]
Uses affine conversions (factor + offset) for Celsius and Fahrenheit.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Temperature |
any (TemperatureUnit) |
- |
| Unit-specific | Kelvin |
Kelvin |
K |
| Unit-specific | Celsius |
Celsius |
°C |
| Unit-specific | Fahrenheit |
Fahrenheit |
°F |
Electric Current [I¹]
The SI base unit of electric current.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | ElectricCurrent |
any (ElectricCurrentUnit) |
- |
| Unit-specific | Ampere |
Ampere |
A |
| Unit-specific | Kiloampere |
Kiloampere |
kA |
| Unit-specific | Milliampere |
Milliampere |
mA |
| Unit-specific | Microampere |
Microampere |
μA |
| Unit-specific | Nanoampere |
Nanoampere |
nA |
Area [L²]
Derived from Length × Length.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Area |
any | - |
| System-specific | MetricArea |
any metric (MetricAreaUnit) |
- |
| System-specific | ImperialArea |
any imperial (ImperialAreaUnit) |
- |
| Unit-specific | SquareMeter |
SquareMeter |
m² |
| Unit-specific | SquareKilometer |
SquareKilometer |
km² |
| Unit-specific | SquareCentimeter |
SquareCentimeter |
cm² |
| Unit-specific | SquareMillimeter |
SquareMillimeter |
mm² |
| Unit-specific | SquareDecimeter |
SquareDecimeter |
dm² |
| Unit-specific | Hectare |
Hectare |
ha |
| Unit-specific | Are |
Are |
a |
| Unit-specific | SquareFoot |
SquareFoot |
ft² |
| Unit-specific | SquareInch |
SquareInch |
in² |
| Unit-specific | SquareYard |
SquareYard |
yd² |
| Unit-specific | SquareMile |
SquareMile |
mi² |
| Unit-specific | Acre |
Acre |
ac |
Volume [L³]
Derived from Length × Length × Length. Includes gas measurement units.
Velocity [L¹T⁻¹]
Derived from Length ÷ Time.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Velocity |
any | - |
| System-specific | MetricVelocity |
any metric (MetricVelocityUnit) |
- |
| System-specific | ImperialVelocity |
any imperial (ImperialVelocityUnit) |
- |
| Unit-specific | MeterPerSecond |
MeterPerSecond |
m/s |
| Unit-specific | KilometerPerHour |
KilometerPerHour |
km/h |
| Unit-specific | CentimeterPerSecond |
CentimeterPerSecond |
cm/s |
| Unit-specific | MillimeterPerSecond |
MillimeterPerSecond |
mm/s |
| Unit-specific | MilePerHour |
MilePerHour |
mph |
| Unit-specific | FootPerSecond |
FootPerSecond |
ft/s |
| Unit-specific | Knot |
Knot |
kn |
Acceleration [L¹T⁻²]
Derived from Velocity ÷ Time.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Acceleration |
any | - |
| System-specific | MetricAcceleration |
any metric (MetricAccelerationUnit) |
- |
| System-specific | ImperialAcceleration |
any imperial (ImperialAccelerationUnit) |
- |
| Unit-specific | MeterPerSecondSquared |
MeterPerSecondSquared |
m/s² |
| Unit-specific | CentimeterPerSecondSquared |
CentimeterPerSecondSquared |
cm/s² |
| Unit-specific | MillimeterPerSecondSquared |
MillimeterPerSecondSquared |
mm/s² |
| Unit-specific | Gal |
Gal |
Gal |
| Unit-specific | StandardGravity |
StandardGravity |
g |
| Unit-specific | FootPerSecondSquared |
FootPerSecondSquared |
ft/s² |
| Unit-specific | InchPerSecondSquared |
InchPerSecondSquared |
in/s² |
Force [L¹M¹T⁻²]
Derived from Mass × Acceleration.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Force |
any | - |
| System-specific | SIForce |
any SI (SIForceUnit) |
- |
| System-specific | ImperialForce |
any imperial (ImperialForceUnit) |
- |
| Unit-specific | Newton |
Newton |
N |
| Unit-specific | Kilonewton |
Kilonewton |
kN |
| Unit-specific | Meganewton |
Meganewton |
MN |
| Unit-specific | Millinewton |
Millinewton |
mN |
| Unit-specific | Micronewton |
Micronewton |
μN |
| Unit-specific | Dyne |
Dyne |
dyn |
| Unit-specific | PoundForce |
PoundForce |
lbf |
| Unit-specific | OunceForce |
OunceForce |
ozf |
| Unit-specific | Kip |
Kip |
kip |
| Unit-specific | Poundal |
Poundal |
pdl |
Pressure [L⁻¹M¹T⁻²]
Derived from Force ÷ Area.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Pressure |
any | - |
| System-specific | SIPressure |
any SI (SIPressureUnit) |
- |
| System-specific | ImperialPressure |
any imperial (ImperialPressureUnit) |
- |
| Unit-specific | Pascal |
Pascal |
Pa |
| Unit-specific | Hectopascal |
Hectopascal |
hPa |
| Unit-specific | Kilopascal |
Kilopascal |
kPa |
| Unit-specific | Megapascal |
Megapascal |
MPa |
| Unit-specific | Gigapascal |
Gigapascal |
GPa |
| Unit-specific | Bar |
Bar |
bar |
| Unit-specific | Millibar |
Millibar |
mbar |
| Unit-specific | Atmosphere |
Atmosphere |
atm |
| Unit-specific | Torr |
Torr |
Torr |
| Unit-specific | PoundPerSquareInch |
PoundPerSquareInch |
psi |
| Unit-specific | PoundPerSquareFoot |
PoundPerSquareFoot |
psf |
| Unit-specific | InchOfMercury |
InchOfMercury |
inHg |
| Unit-specific | InchOfWater |
InchOfWater |
inH₂O |
Energy [L²M¹T⁻²]
Work and heat. Includes electrical and thermal units.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Energy |
any | - |
| System-specific | SIEnergy |
any SI (SIEnergyUnit) |
- |
| System-specific | ElectricEnergy |
any electric (ElectricEnergyUnit) |
- |
| System-specific | ThermalEnergy |
any thermal (ThermalEnergyUnit) |
- |
| Unit-specific | Joule |
Joule |
J |
| Unit-specific | Kilojoule |
Kilojoule |
kJ |
| Unit-specific | Megajoule |
Megajoule |
MJ |
| Unit-specific | WattHour |
WattHour |
Wh |
| Unit-specific | KilowattHour |
KilowattHour |
kWh |
| Unit-specific | MegawattHour |
MegawattHour |
MWh |
| Unit-specific | GigawattHour |
GigawattHour |
GWh |
| Unit-specific | Calorie |
Calorie |
cal |
| Unit-specific | Kilocalorie |
Kilocalorie |
kcal |
| Unit-specific | BritishThermalUnit |
BritishThermalUnit |
BTU |
Power [L²M¹T⁻³]
Derived from Energy ÷ Time.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Power |
any | - |
| System-specific | SIPower |
any SI (SIPowerUnit) |
- |
| System-specific | ImperialPower |
any imperial (ImperialPowerUnit) |
- |
| Unit-specific | Watt |
Watt |
W |
| Unit-specific | Milliwatt |
Milliwatt |
mW |
| Unit-specific | Kilowatt |
Kilowatt |
kW |
| Unit-specific | Megawatt |
Megawatt |
MW |
| Unit-specific | Gigawatt |
Gigawatt |
GW |
| Unit-specific | MechanicalHorsepower |
MechanicalHorsepower |
hp |
| Unit-specific | ElectricalHorsepower |
ElectricalHorsepower |
hp(E) |
| Unit-specific | MetricHorsepower |
MetricHorsepower |
PS |
| Unit-specific | FootPoundPerSecond |
FootPoundPerSecond |
ft⋅lbf/s |
| Unit-specific | BTUPerHour |
BTUPerHour |
BTU/h |
Density [L⁻³M¹]
Derived from Mass ÷ Volume.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Density |
any | - |
| System-specific | SIDensity |
any SI (SIDensityUnit) |
- |
| System-specific | ImperialDensity |
any imperial (ImperialDensityUnit) |
- |
| Unit-specific | KilogramPerCubicMeter |
KilogramPerCubicMeter |
kg/m³ |
| Unit-specific | GramPerCubicMeter |
GramPerCubicMeter |
g/m³ |
| Unit-specific | GramPerCubicCentimeter |
GramPerCubicCentimeter |
g/cm³ |
| Unit-specific | GramPerLiter |
GramPerLiter |
g/L |
| Unit-specific | KilogramPerLiter |
KilogramPerLiter |
kg/L |
| Unit-specific | MilligramPerCubicMeter |
MilligramPerCubicMeter |
mg/m³ |
| Unit-specific | TonnePerCubicMeter |
TonnePerCubicMeter |
t/m³ |
| Unit-specific | PoundPerCubicFoot |
PoundPerCubicFoot |
lb/ft³ |
| Unit-specific | PoundPerCubicInch |
PoundPerCubicInch |
lb/in³ |
| Unit-specific | PoundPerGallon |
PoundPerGallon |
lb/gal |
| Unit-specific | OuncePerCubicInch |
OuncePerCubicInch |
oz/in³ |
| Unit-specific | SlugPerCubicFoot |
SlugPerCubicFoot |
slug/ft³ |
Frequency [T⁻¹]
Derived from 1 ÷ Time.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Frequency |
any (FrequencyUnit) |
- |
| Unit-specific | Hertz |
Hertz |
Hz |
| Unit-specific | Millihertz |
Millihertz |
mHz |
| Unit-specific | Kilohertz |
Kilohertz |
kHz |
| Unit-specific | Megahertz |
Megahertz |
MHz |
| Unit-specific | Gigahertz |
Gigahertz |
GHz |
| Unit-specific | Terahertz |
Terahertz |
THz |
| Unit-specific | RevolutionPerMinute |
RevolutionPerMinute |
RPM |
| Unit-specific | RevolutionPerSecond |
RevolutionPerSecond |
RPS |
| Unit-specific | BeatsPerMinute |
BeatsPerMinute |
BPM |
Angle [dimensionless]
Plane angle measurement.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Angle |
any (AngleUnit) |
- |
| Unit-specific | Radian |
Radian |
rad |
| Unit-specific | Milliradian |
Milliradian |
mrad |
| Unit-specific | Degree |
Degree |
° |
| Unit-specific | Arcminute |
Arcminute |
′ |
| Unit-specific | Arcsecond |
Arcsecond |
″ |
| Unit-specific | Gradian |
Gradian |
gon |
| Unit-specific | Revolution |
Revolution |
rev |
| Unit-specific | Turn |
Turn |
tr |
Electric Potential [L²M¹T⁻³I⁻¹]
Voltage. Derived from Power ÷ Current.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | ElectricPotential |
any (ElectricPotentialUnit) |
- |
| Unit-specific | Volt |
Volt |
V |
| Unit-specific | Megavolt |
Megavolt |
MV |
| Unit-specific | Kilovolt |
Kilovolt |
kV |
| Unit-specific | Millivolt |
Millivolt |
mV |
| Unit-specific | Microvolt |
Microvolt |
μV |
Electric Resistance [L²M¹T⁻³I⁻²]
Derived from Voltage ÷ Current.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | ElectricResistance |
any (ElectricResistanceUnit) |
- |
| Unit-specific | Ohm |
Ohm |
Ω |
| Unit-specific | Megaohm |
Megaohm |
MΩ |
| Unit-specific | Kiloohm |
Kiloohm |
kΩ |
| Unit-specific | Milliohm |
Milliohm |
mΩ |
| Unit-specific | Microohm |
Microohm |
μΩ |
Electric Capacitance [L⁻²M⁻¹T⁴I²]
Ability to store electric charge.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | ElectricCapacitance |
any (ElectricCapacitanceUnit) |
- |
| Unit-specific | Farad |
Farad |
F |
| Unit-specific | Millifarad |
Millifarad |
mF |
| Unit-specific | Microfarad |
Microfarad |
μF |
| Unit-specific | Nanofarad |
Nanofarad |
nF |
| Unit-specific | Picofarad |
Picofarad |
pF |
Electric Charge [T¹I¹]
Derived from Current × Time.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | ElectricCharge |
any (ElectricChargeUnit) |
- |
| Unit-specific | Coulomb |
Coulomb |
C |
| Unit-specific | Millicoulomb |
Millicoulomb |
mC |
| Unit-specific | Microcoulomb |
Microcoulomb |
μC |
| Unit-specific | AmpereHour |
AmpereHour |
Ah |
| Unit-specific | MilliampereHour |
MilliampereHour |
mAh |
Inductance [L²M¹T⁻²I⁻²]
Property of an electrical conductor.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Inductance |
any (InductanceUnit) |
- |
| Unit-specific | Henry |
Henry |
H |
| Unit-specific | Millihenry |
Millihenry |
mH |
| Unit-specific | Microhenry |
Microhenry |
μH |
| Unit-specific | Nanohenry |
Nanohenry |
nH |
Magnetic Flux [L²M¹T⁻²I⁻¹]
Measure of total magnetic field through a surface.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | MagneticFlux |
any (MagneticFluxUnit) |
- |
| Unit-specific | Weber |
Weber |
Wb |
| Unit-specific | Milliweber |
Milliweber |
mWb |
| Unit-specific | Microweber |
Microweber |
μWb |
| Unit-specific | Maxwell |
Maxwell |
Mx |
Luminous Intensity [J¹]
The SI base unit of luminous intensity.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | LuminousIntensity |
any (LuminousIntensityUnit) |
- |
| Unit-specific | Candela |
Candela |
cd |
| Unit-specific | Kilocandela |
Kilocandela |
kcd |
| Unit-specific | Millicandela |
Millicandela |
mcd |
| Unit-specific | Microcandela |
Microcandela |
μcd |
Luminous Flux [J¹]
Total amount of visible light emitted.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | LuminousFlux |
any (LuminousFluxUnit) |
- |
| Unit-specific | Lumen |
Lumen |
lm |
| Unit-specific | Kilolumen |
Kilolumen |
klm |
| Unit-specific | Millilumen |
Millilumen |
mlm |
Illuminance [L⁻²J¹]
Derived from Luminous Flux ÷ Area.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | Illuminance |
any (IlluminanceUnit) |
- |
| Unit-specific | Lux |
Lux |
lx |
| Unit-specific | Kilolux |
Kilolux |
klx |
| Unit-specific | Millilux |
Millilux |
mlx |
| Unit-specific | FootCandle |
FootCandle |
fc |
Calorific Value [L⁻¹M¹T⁻²]
Energy per unit volume. Used for gas billing.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | CalorificValue |
any | - |
| System-specific | MetricCalorificValue |
any metric (MetricCalorificValueUnit) |
- |
| System-specific | ImperialCalorificValue |
any imperial (ImperialCalorificValueUnit) |
- |
| Unit-specific | JoulePerCubicMeter |
JoulePerCubicMeter |
J/m³ |
| Unit-specific | KilojoulePerCubicMeter |
KilojoulePerCubicMeter |
kJ/m³ |
| Unit-specific | MegajoulePerCubicMeter |
MegajoulePerCubicMeter |
MJ/m³ |
| Unit-specific | GigajoulePerCubicMeter |
GigajoulePerCubicMeter |
GJ/m³ |
| Unit-specific | BTUPerCubicFoot |
BTUPerCubicFoot |
BTU/ft³ |
| Unit-specific | ThermPerCubicFoot |
ThermPerCubicFoot |
thm/ft³ |
Digital Information [D¹]
Data storage capacity. Supports SI (decimal) and IEC (binary) prefixes.
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | DigitalInformation |
any | - |
| System-specific | SI\DigitalInformation |
any SI (SIDigitalUnit) |
- |
| System-specific | SI\BitDigitalInformation |
any SI bit (SIBitUnit) |
- |
| System-specific | SI\ByteDigitalInformation |
any SI byte (SIByteUnit) |
- |
| System-specific | IEC\DigitalInformation |
any IEC (IECDigitalUnit) |
- |
| System-specific | IEC\BitDigitalInformation |
any IEC bit (IECBitUnit) |
- |
| System-specific | IEC\ByteDigitalInformation |
any IEC byte (IECByteUnit) |
- |
SI Units (decimal, powers of 10):
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Unit-specific | Bit |
Bit |
b |
| Unit-specific | Kilobit |
Kilobit |
Kb |
| Unit-specific | Megabit |
Megabit |
Mb |
| Unit-specific | Gigabit |
Gigabit |
Gb |
| Unit-specific | Terabit |
Terabit |
Tb |
| Unit-specific | Petabit |
Petabit |
Pb |
| Unit-specific | Byte |
Byte |
B |
| Unit-specific | Kilobyte |
Kilobyte |
KB |
| Unit-specific | Megabyte |
Megabyte |
MB |
| Unit-specific | Gigabyte |
Gigabyte |
GB |
| Unit-specific | Terabyte |
Terabyte |
TB |
| Unit-specific | Petabyte |
Petabyte |
PB |
IEC Units (binary, powers of 2):
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Unit-specific | Kibibit |
Kibibit |
Kib |
| Unit-specific | Mebibit |
Mebibit |
Mib |
| Unit-specific | Gibibit |
Gibibit |
Gib |
| Unit-specific | Tebibit |
Tebibit |
Tib |
| Unit-specific | Pebibit |
Pebibit |
Pib |
| Unit-specific | Kibibyte |
Kibibyte |
KiB |
| Unit-specific | Mebibyte |
Mebibyte |
MiB |
| Unit-specific | Gibibyte |
Gibibyte |
GiB |
| Unit-specific | Tebibyte |
Tebibyte |
TiB |
| Unit-specific | Pebibyte |
Pebibyte |
PiB |
Data Transfer Rate [D¹T⁻¹]
Measures the speed of data transmission, commonly used for network bandwidth, internet connection speeds, and file transfer rates. Like Digital Information, this quantity supports both SI (decimal) and IEC (binary) prefixes. ISPs and network equipment typically advertise speeds using SI units (e.g., "100 Mbps fiber"), while operating systems often report actual transfer rates in IEC units (e.g., "12 MiB/s"). This distinction matters because 100 Mbps (megabits per second) equals 12.5 MB/s (megabytes per second) but only about 11.92 MiB/s (mebibytes per second).
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Generic | DataTransferRate |
any | - |
| System-specific | SI\TransferRate |
any SI (SITransferRateUnit) |
- |
| System-specific | SI\BitTransferRate |
any SI bit (BitTransferRateUnit) |
- |
| System-specific | SI\ByteTransferRate |
any SI byte (ByteTransferRateUnit) |
- |
| System-specific | IEC\TransferRate |
any IEC (IECTransferRateUnit) |
- |
| System-specific | IEC\BitTransferRate |
any IEC bit (IECBitTransferRateUnit) |
- |
| System-specific | IEC\ByteTransferRate |
any IEC byte (IECByteTransferRateUnit) |
- |
SI Units:
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Unit-specific | BitPerSecond |
BitPerSecond |
bps |
| Unit-specific | KilobitPerSecond |
KilobitPerSecond |
kbps |
| Unit-specific | MegabitPerSecond |
MegabitPerSecond |
Mbps |
| Unit-specific | GigabitPerSecond |
GigabitPerSecond |
Gbps |
| Unit-specific | BytePerSecond |
BytePerSecond |
B/s |
| Unit-specific | KilobytePerSecond |
KilobytePerSecond |
KB/s |
| Unit-specific | MegabytePerSecond |
MegabytePerSecond |
MB/s |
| Unit-specific | GigabytePerSecond |
GigabytePerSecond |
GB/s |
IEC Units:
| Scope | Class | Unit | Symbol |
|---|---|---|---|
| Unit-specific | KibibitPerSecond |
KibibitPerSecond |
Kibps |
| Unit-specific | MebibitPerSecond |
MebibitPerSecond |
Mibps |
| Unit-specific | GibibitPerSecond |
GibibitPerSecond |
Gibps |
| Unit-specific | KibibytePerSecond |
KibibytePerSecond |
KiB/s |
| Unit-specific | MebibytePerSecond |
MebibytePerSecond |
MiB/s |
| Unit-specific | GibibytePerSecond |
GibibytePerSecond |
GiB/s |
Testing
# Run tests make tests # Run PHPStan make phpstan # Generate coverage report make coverage # Show coverage in terminal make coverage-text
Docker Support
# Build container make setup # Get inside PHP container make php
Built with ❤️ by AndanteProject team.
