nmarfurt / measurements
A PHP library for representing and converting dimensional units of measure.
Installs: 135 593
Dependents: 1
Suggesters: 0
Security: 0
Stars: 15
Watchers: 3
Forks: 4
Open Issues: 0
Requires
- php: ^7.2 | ^8.0
Requires (Dev)
- phpunit/phpunit: ^8 | ^9
README
About
This is a PHP library for representing and converting dimensional units of measure. This is inspired by the Measurement API in the Apple Foundation Framework.
Installation
The package can be installed via Composer:
composer require nmarfurt/measurements
Library Classes
Unit
Unit
is the abstract superclass of units. Each instance of an Unit
subclass consists of a symbol, which can be used to create string representations of Measurement
objects.
Dimension
Dimension
is an abstract subclass of Unit
that represents unit families or a dimensional unit of measure, which can be converted into different units of the same type.
Each instance of an Dimension
subclass has a converter, which is used to represent the unit in terms of the dimension's base unit provided by the baseUnit()
method.
The library provides concrete subclasses for many of the most common types of physical units (listed below). If you need a custom unit type to represent a custom or derived unit, you can subclass
Dimension
. If you need to represent dimensionless units, subclassUnit
directly.
UnitConverter
A UnitConverter
describes how to convert a unit to and from the base unit of its dimension. UnitConverterLinear
is a UnitConverter
subclass for converting between units using a linear equation. You can define your own converters if needed.
Measurement
A Measurement
object represents a measured quantity, using a unit of measure and a value. The Measurement
class provides a programmatic interface to converting measurements into different units, as well as calculating the sum or difference between two measurements.
Measurement
objects are initialized with a Unit
object and double value. They are immutable and cannot be changed after being created.
The library provides specific subclasses (so called Quantities) for measurements that correspond to the provided units (see the list below).
Provided Units & Quantities
The library provides concrete subclasses for many of the most common types of physical units:
Usage
Using Measurements
You can define measurements as follows:
use Measurements\Measurement; use Measurements\Units\UnitLength; use Measurements\Units\UnitDuration; $length = new Measurement(4.48, UnitLength::meters()); echo $length; // = 4.48 m $duration = new Measurement(1.5, UnitDuration::hours()); echo $duration; // = 1.5 hr
You may want to enforce the unit type of a measurement by using the provided measurement subclasses (aka Quantities):
use Measurements\Units\UnitLength; use Measurements\Units\UnitDuration; use Measurements\Quantities\Length; use Measurements\Quantities\Duration; $length = new Length(4.48, UnitLength::meters()); echo $length; // = 4.48 m $duration = new Duration(1.5, UnitDuration::hours()); echo $duration; // = 1.5 hr $invalid = new Length(4.48, UnitDuration::hours()); // Will throw a UnitException exception
The Quantities objects also provide the benefit of an expressive syntax to create measurements. They make use of the __callStatic()
magic-method to create a new instance by resolving the derived dimension.
use Measurements\Quantities\Length; use Measurements\Quantities\Duration; $length = Length::meters(4.48); echo $length; // = 4.48 m $duration = Duration::hours(1.5); echo $duration; // = 1.5 hr $invalid = Length::hours(4.48); // Will throw a BadMethodCallException exception
Some of the Measurement subclasses expose convenience methods to easily create instances from other measurements.
use Measurements\Quantities\Length; use Measurements\Quantities\Duration; $distance = Length::kilometers(18); $time = Duration::hours(1); $speed = Speed::fromLengthAndDuration($distance, $time); echo $speed->toString(); // 5 m/s
Converting Measurements
Measurement objects of the same dimension can be converted from one unit of measure to another.
use Measurements\Measurement; use Measurements\Units\UnitLength; $meters = new Measurement(4.48, UnitLength::meters()); $centimeters = $meters->convertTo(UnitLength::centimeters()); echo $centimeters; // = 448 cm
Measurements created as Quantities objects also provide a short syntax to convert them. They make use of the __call()
magic-method to resolve the derived dimension.
use Measurements\Quantities\Length; $meters = Length::meters(4.48); $centimeters = $meters->toCentimeters(); echo $centimeters; // = 448 cm
Making Arithmetic Operations
Measurement objects support different operations, including add
(+
), subtract
(-
), multiply
(*
) and divide
(/
).
Since Measurement objects are immutable, new instances are returned.
use Measurements\Measurement; use Measurements\Units\UnitLength; $first = new Measurement(4.48, UnitLength::meters()); $second = new Measurement(2.02, UnitLength::meters()); echo $first->add($second); // = 6.5 m echo $first->subtract($second); // = 2.46 m echo $first->multiplyBy($second); // = 9.0496 m echo $first->divideBy($second); // = 2.2178217822 m
Conversions are automatically applied while making operations on measurements with different units. The returned measurement is defined in the base unit.
use Measurements\Measurement; use Measurements\Units\UnitLength; $decimeters = new Measurement(44.8, UnitLength::decimeters()); $centimeters = new Measurement(202, UnitLength::centimeters()); echo $decimeters->add($centimeters); // = 6.5 m echo $decimeters->subtract($centimeters); // = 2.46 m echo $decimeters->multiplyBy($centimeters); // = 9.0496 m echo $decimeters->divideBy($centimeters); // = 2.2178217822 m
It is also possible to make arithmetic operations on a measurement using values.
use Measurements\Measurement; use Measurements\Units\UnitLength; $centimeters = new Measurement(42, UnitLength::centimeters()); echo $centimeters->addValue(8); // = 50 cm echo $centimeters->subtractValue(12); // = 30 cm echo $centimeters->multiplyByValue(2); // = 84 cm echo $centimeters->divideByValue(2); // = 21 cm
Working with Custom Units
In addition to provided units, you can define custom units. Custom units can be initialized from a symbol and converter of an existing type or implemented as a class method of an existing type for additional convenience. You can also define your own Dimension
subclass to represent an entirely new unit dimension.
Initializing a Custom Unit with a Specified Symbol and Definition
The simplest way to define a custom unit is to create a new instance of an existing Dimension
subclass.
For example, let define a jump as a custom, nonstandard unit of length (1 jump = 1.82 m). You can create a new instance of UnitLength
as follows:
$jump = new UnitLength("jump", new UnitConverterLinear(1.82));
Extending Existing Dimension Subclasses
Alternatively, you can extend an existing Dimension
subclass to define a new unit.
For example, let define our new jump unit as custom subclass:
class UnitJump extends UnitLength { public static function jumps() { return new static("jump", new UnitConverterLinear(1.82)); } }
Creating a Custom Dimension Subclass
You can create a new subclass of Dimension
to describe a new unit dimension.
For example, let define units for digital data. In computing and telecommunications, a unit of information is the capacity of some standard data storage system or communication channel, used to measure the capacities of other systems and channels. Bytes, or multiples thereof, are common units used to specify the sizes of computer files and the capacity of storage units.
You can implement a UnitDigitalData
class that defines units of digital information as follows:
class UnitDigitalData extends Dimension { public static function baseUnit() { return static::bytes(); } public static function bytes() { return new UnitDigitalData("B", new UnitConverterLinear(1.0)); } public static function kilobytes() { return new UnitDigitalData("kB", new UnitConverterLinear(1000)); } public static function megabytes() { return new UnitDigitalData("MB", new UnitConverterLinear(1000000)); } public static function kibibytes() { return new UnitDigitalData("KiB", new UnitConverterLinear(1024)); } public static function mebibytes() { return new UnitDigitalData("MiB", new UnitConverterLinear(1048576)); } // ... }
Generating API Documentation
phpdoc -d ./src/ -t ./doc/generated --template="xml"
phpdocmd ./doc/generated/structure.xml doc/
License
This library is open-sourced software licensed under the MIT license.