PHP code example of andanteproject / measurement

1. Go to this page and download the library: Download andanteproject/measurement library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

andanteproject / measurement example snippets


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"

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
}

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
);

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"

$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)

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)

$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)

// 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)

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

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"

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());

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)

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)

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

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());

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
        );
    }
}

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;
    }
}

use Andante\Measurement\Contract\QuantityInterface;

interface ViscosityInterface extends QuantityInterface
{
}

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;
    }
}

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
        );
    }
}

// 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

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);

// 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'