php-crossover-calculator/src/Scientific/Quantity.php

87 lines
2.0 KiB
PHP

<?php
namespace Scientific;
use InvalidArgumentException;
abstract class Quantity
{
/*
* https://en.wikipedia.org/wiki/Metric_prefix
*/
private const METRIC_PREFIXES = [
'yotta' => 'Y',
'zetta' => 'Z',
'exa' => 'E',
'peta' => 'P',
'tera' => 'T',
'giga' => 'G',
'mega' => 'M',
'kilo' => 'k',
'hecto' => 'h',
'deca' => 'da',
'unit' => '',
'deci' => 'd',
'centi' => 'c',
'milli' => 'm',
'micro' => 'μ',
'nano' => 'n',
'pico' => 'p',
'femto' => 'f',
'atto' => 'a',
'zepto' => 'z',
'yocto' => 'y',
];
abstract protected function getSymbol(): string;
abstract protected function getName(): string;
public function __construct(
private Unit $value
)
{
}
final public static function fromValue(float $value): static
{
return new static(new Unit($value));
}
final public function getValue(): Unit
{
return $this->value;
}
final public function format(string $prefix = 'auto'): string
{
if ($prefix === 'auto') {
$prefix = $this->getAppropriatePrefix();
} else if (!method_exists($this->value, $prefix)) {
throw new InvalidArgumentException('Invalid size: ' . $prefix);
}
$value = $this->value->{$prefix}();
$prefix = self::METRIC_PREFIXES[$prefix] ?? '?';
$symbol = $this->getSymbol();
return sprintf('%.3g %s%s', $value, $prefix, $symbol);
}
private function getAppropriatePrefix(): string
{
foreach (array_keys(self::METRIC_PREFIXES) as $prefix) {
$value = $this->value->{$prefix}();
if ($value >= 1. && $value < 1000.) {
return $prefix;
}
}
return 'unit';
}
public function __toString(): string
{
return $this->format();
}
}