A library for handling physical quantities and the units of measure in which they're represented.

Overview

PHP Units of Measure

master: Build Status

Introduction

This is a PHP library for representing and converting physical units of measure. The utility of this library is in encapsulating physical quantities in such a way that you don't have to keep track of which unit they're represented in. For instance:

use PhpUnitsOfMeasure\PhysicalQuantity\Length;

$height = new Length(6.16, 'feet');
echo $height->toUnit('m');

// would print 1.87757, which is 6.16 feet in meters.

Having this abstraction allows you to create interfaces that accept physical quantities without requiring them to be in a particular unit. For example, this function assumes the height is a float of a particular unit (presumably feet), and is therefore undesirably tied to a specific unit of measure:

// Tied to a specific unit of measure
function isTooTallToRideThisTrain( $height )
{
  return $height > 5;
}

// Calling the function requires that you first convert whatever quantity
// you have into the expected units:
isTooTallToRideThisTrain(2 / 0.3048);

Whereas this version using this library allows for height to be provided in whatever unit is convenient:

use PhpUnitsOfMeasure\PhysicalQuantity\Length;

// Free to operate on lengths in any unit of measure
function isTooTallToRideThisTrain( Length $height )
{
  return $height->toUnit('ft') > 5;
}

// Calling the function now allows any unit to be used:
isTooTallToRideThisTrain( new Length(2, 'm') );

Installation

This library is best included in your projects via Composer. See the Composer website for more details, and see the Packagist.org site for this library.

If you'd prefer to manually include this library as a dependency in your project, then it is recommended that you use a PSR-4 compliant PHP autoloader. The mapping between this project's root namespace and its base directory is:

  • vendor namespace 'PhpUnitsOfMeasure' maps to the library's base directory 'source/'

See the documentation of your autoloader for further instructions.

Project Tags and Versions

This project follows the guidelines set out in Semantic Versioning 2.0.0. In general, versions are of the form 'X.Y.Z', and increments to X denote backward-incompatible major changes.

It is recommended that if your project includes this project as a dependency and you are using an automated dependency management tool such as Composer, then you should 'pin' the major version (X) and allow only variations in 'Y' (minor changes) and 'Z' (bugfixes). See the documentation of your dependency manager for more details.

Use

Conversion

As in the examples above, the basic usage of this library is in representing physical quantities and converting between typical units of measure. For example:

use PhpUnitsOfMeasure\PhysicalQuantity\Mass;

$quantity = new Mass(6, 'lbs');
echo $quantity->toUnit('g');

It's also possible to implicity cast a quantity to a string, which will display its original value:

use PhpUnitsOfMeasure\PhysicalQuantity\Mass;

$quantity = new Mass(6, 'pounds');
echo $quantity; // '6 lbs'

Arithmetic Operators

There's also support for addition and subtraction. The values of the physical quantity objects are immutable, and so these arithmetic methods return new quantity objects representing the results:

use PhpUnitsOfMeasure\PhysicalQuantity\Volume;

$first  = new Volume(6, 'liters');
$second = new Volume(6, 'cups');

$sum = $first->add($second);
echo $sum; // 7.4195292 l

$difference = $first->subtract($second);
echo $difference; // 4.5804708 l

Adding new Units of Measure to Existing Quantities

Ocassionally, you will need to add a new unit of measure to a pre-existing quantity.

For example, let's say in a project you need a new measure of length, called "cubits". You have two options: you can permanently add the new unit of measure to a new child class of the \PhpUnitsOfMeasure\PhysicalQuantity\Length class (or add it directly to that class and submit a pull request to get it added upstream, if appropriate), or you can add the unit temporarily at run time, inside your calling code.

Adding a New Unit of Measure at Runtime

To add a new unit of measure to an existing quantity at run time, you'd do this:

use PhpUnitsOfMeasure\PhysicalQuantity\Length;
use PhpUnitsOfMeasure\PhysicalQuantity\UnitOfMeasure;

// It's ok to create objects with cubits before the new unit is registered, since
// the conversion doesn't happen until an output method is called
$length = new Length(14, 'cubits');

// Build a new Unit of Measure object which represents the new unit, and which
// knows how to convert between the new unit and the quantity's native unit
// (in this case, meters).
$cubit = new UnitOfMeasure(

    // This is the official name of this unit - typically it's the standard
    // abbreviation
    'cb',

    // The second parameter is a function that converts from the native unit
    // to this unit
    function ($valueInNativeUnit) {
        return $valueInNativeUnit / 0.4572;
    },

    // The third parameter is a function that converts from this unit to the
    // native unit
    function ($valueInThisUnit) {
        return $valueInThisUnit * 0.4572;
    }
);

// Any alias names for this unit can be added here, to make it easier to use
// variations
$cubit->addAlias('cubit');
$cubit->addAlias('cubits');

// Register the new unit of measure with the quantity class
Length::addUnit($cubit);

// Now that the unit is registered, you can cast the measurement to any other
// measure of length
echo $length->toUnit('feet'); // '21'
Shorthand Factory Methods

Note that when creating instances of UnitOfMeasure, there are a couple of convenience static factory methods. The first lets you instantiate units of measure which have linear scaling factors from the native unit. That is, the conversion function fits into the form 'Value in the native unit of measure' = 'Value in this unit of measure' * F, where F is the scaling factor.

$megameter = UnitOfMeasure::linearUnitFactory('Mm', 1e6);
$megameter->addAlias('Megameter');
$megameter->addAlias('Megametre');
Length::addUnit($megameter);

The other convenience method is a special case of the above scaling factor factory method where the scaling factor is set to exactly 1, and serves as a convenient way of generating the native unit of measure. All physical quantities must have one and only one native unit, so this method will probably only be called once per Physical Quantity class:

$meter = UnitOfMeasure::nativeUnitFactory('m');
$meter->addAlias('meter');
$meter->addAlias('metre');
Length::addUnit($meter);
Automatically Generating Metric Units

For units that use the metric system, there's a convenience trait available for classes which implementPhysicalQuantityInterface which will automatically generate the full continuum of metric units from a single unit. For instance:

namespace PhpUnitsOfMeasure\PhysicalQuantity;

use PhpUnitsOfMeasure\AbstractPhysicalQuantity;
use PhpUnitsOfMeasure\UnitOfMeasure;
use PhpUnitsOfMeasure\HasSIUnitsTrait;

class Mass extends AbstractPhysicalQuantity
{
    use HasSIUnitsTrait;

    protected static $unitDefinitions;

    protected static function initialize()
    {
        // Kilogram
        $kilogram = UnitOfMeasure::nativeUnitFactory('kg');
        $kilogram->addAlias('kilogram');
        $kilogram->addAlias('kilograms');
        static::addUnit($kilogram);

        static::addMissingSIPrefixedUnits(
            $kilogram,
            1e-3,
            '%pg',
            [
                '%Pgram',
                '%Pgrams',
            ]
        );
    }
}

Here we're generating the native unit for mass, kilogram, adding it to the quantity as usual, and then using it to generate the spectrum of SI units by calling the addMissingSIPrefixedUnits() static method provided by the HasSIUnitsTrait trait.

Of note, the second parameter (1e-3) is denoting that while kilograms are the native unit for Mass, there's a factor of 1/1000 between the kilogram and the base metric unit of mass: the gram. For units such as seconds or meters where the native unit for the physical quantity is also the base unit for the metric prefix system, this factor would be 1.

The 3rd and 4th parameters contain templates for the units' names and alternate aliases, respectively. The replacement strings '%p' and '%P' are used to denote the abbreviated and long-form metric prefixes. For instance, '%pg' would generate the series ..., 'mg', 'cg', 'dg', 'g', ..., while the template '%Pgram' would generate the series ..., 'milligram', 'centigram', 'decigram', 'gram', ... .

Permanently Adding a New Unit of Measure to a Physical Quantity

The examples above for adding new units of measure to physical quantities allow you to register new units for the duration of the PHP execution, but are lost once execution terminates; it would be necessary to repeat this process every time you created a new program with Length measurements and wanted to use cubits.

A new unit of measure can be permanently added to a Physical Quantity class by essentially the same process as the one-time examples, only it would be done inside the initialize() method of the quantity class. For example:

namespace PhpUnitsOfMeasure\PhysicalQuantity;

use PhpUnitsOfMeasure\AbstractPhysicalQuantity;
use PhpUnitsOfMeasure\UnitOfMeasure;

class Length extends AbstractPhysicalQuantity
{
    protected static $unitDefinitions;

    protected static function initialize()
    {
        // ...
        // ...
        // Here's all the pre-existing unit definitions for Length
        // ...
        // ...

        // Cubit
        $cubit = UnitOfMeasure::linearUnitFactory('cb', 0.4572);
        $cubit->addAlias('cubit');
        $cubit->addAlias('cubits');
        static::addUnit($cubit);
    }
}

Now any program which uses Length will start with the cubits unit already built in. Note that here we used the more concise linear unit factory method, but the result is equivalent to the expanded form calling the UnitOfMeasure constructor, as used above. Also, notice that the static keyword was used instead of the class name, though either would be acceptable in this case.

Adding New Physical Quantities

Physical quantities are categories of measurable values, like mass, length, force, etc.

For physical quantities that are not already present in this library, it will be necessary to write a class to support a new one. All physical quantities implement the \PhpUnitsOfMeasure\PhysicalQuantityInterface interface, typically extend the \PhpUnitsOfMeasure\AbstractPhysicalQuantity class, and typically have only an initialize() method which creates the quantity's units of measure. See above for typical examples of physical quantity classes and of how to add new units to a quantity class.

Note that every physical quantity has a chosen "native unit" which is typically the SI standard. The main point for this unit is that all of the quantity's other units of measure will convert to and from this chosen native unit. It's important to be aware of a quantity's native unit when writing conversions for new units of measure.

Adding new Aliases to Existing Units

It may come up that the desired unit of measure exists for a given physical quantity, but there's a missing alias for the unit. For example, if you thought 'footses' was an obviously lacking alias for the Length unit 'ft', you could temporarily add the alias like this:

use PhpUnitsOfMeasure\PhysicalQuantity\Length;

// It's ok to use footses here, since the conversion doesn't happen
// until later
$length = new Length(4, 'footses');

// Fetch the unit of measure object that represents the 'ft' unit
$footUnit = Length::getUnit('ft');

// Any alias names for this unit can be added here, to make it easier
// to use variations
$footUnit->addAlias('footses');

// Now that the unit has been modified with its new alias, you can cast
// the measurement to any other measure of length
echo $length->toUnit('m'); // '1.2192'

And of course, if you need to add the alias permanently, you can do so in the initialize() method of the quantity's class, as shown above.

Testing and Contributing

Pull requests are welcome, especially regarding new units of measure or new physical quantities. However, please note that there are many sources for conversion factors, and not all are careful to respect known precision.

In the United States, the standards body for measurement is NIST, and they've published NIST Special Publication 1038 "The International System of Units (SI) - Conversion factors for General Use". This guide contains the approved conversion factors between various units and the base SI units.

Also note that any new physical quantities should have the appropriate SI unit chosen for their native unit of measure.

Pull Requests and Merging

The workflow for this repository goes as follows:

  • To develop new contributions, fork or branch from the master branch of the main repository
  • Pull requests and contribution merges are always made to the master branch of the main repository
  • From time to time, commits of master are tagged and a new version is released
  • At present, there is no support for maintaining bug-fix branches of older project versions. This is something we can revisit if a need arises.

End users of this repository should only use tagged commits in production. Users interested in the current 'soon-to-be-released' code may use master, with the understanding that it may change unexpectedly. All other existing branches (if any) should be considered 'feature' branches in development, and not yet ready for use.

Local Testing Environment

There's a Vagrant virtual machine configuration included which is suitable for running the necessary unit tests. To bring up the machine, make sure you have Vagrant and Virtualbox installed, and from the project root directory:

vagrant up
vagrant ssh
cd /project

Setting Up for Testing

The virtual machine development environment already has Composer installed. Once you're ssh'ed into the virtual machine, install this project's dev dependencies:

rm -rf vendor
composer.phar update --verbose --prefer-dist

Unit Tests

All the tests associated with this project can be manually run with:

vendor/bin/phpunit -c ./tests/phpunit.xml.dist ./tests

CodeSniffer

Codesniffer verifies that coding standards are being met. Once the project is built with development dependencies, you can run the checks with:

vendor/bin/phpcs --encoding=utf-8 --extensions=php --standard=./tests/phpcs.xml -nsp ./

Continuous Integration

The above tests are automatically run against Github commits with Travis-CI.

You might also like...
YCOM Impersonate. Login as selected YCOM user 🧙‍♂️in frontend.

YCOM Impersonate Login as selected YCOM user in frontend. Features: Backend users with admin rights or YCOM[] rights, can be automatically logged in v

This app is to measure the hand and eye co-ordination speed based on the score generated taken from Database
This app is to measure the hand and eye co-ordination speed based on the score generated taken from Database

CoOrdinationSpeedTest Website link: https://skyward-punctures.000webhostapp.com/ Try this only when you are a psychiatrist 😂 😂 This app runs as php

Magento Quickorder module, enables bulk order creation by inputting SKUs & quantities.

Extension User Guide This extension was developed to enable merchants to allow customers to place multiple orders of various quanities quickly, in an

PHP library for determining the physical location of binaries

Bin Locator Library for searching binary files in the operating system. Requirements PHP = 7.4 Installation Library is available as composer reposito

PrestaShop module that allows an ecommerce/brand to display its physical retailers in a map

PrestaShop module that allows an ecommerce/brand to display its physical retailers in a map Features Free of charge: instead of using pa

Library to parse, format and convert byte units

Byte Units This is a utility component for parsing, formatting, converting and manipulating byte units in various formats. Usage ?php // Bytes manip

Library for converting units and sizes in PHP

php-conversion Library for converting units and sizes in PHP. Units supported Acceleration Angle Area Digital information Electric current Frequency F

Library for converting units and sizes in PHP

php-conversion Library for converting units and sizes in PHP. Units supported Acceleration Angle Area Digital information Electric current Frequency F

A class to help convert bytes into other units (kb, mb, etc).

A class to help convert bytes into other units (kb, mb, etc). This package can be used to convert int|float values from bytes to KB, MB and GB as well

Collection of value objects that represent the PHP code units

sebastian/code-unit Collection of value objects that represent the PHP code units. Installation You can add this library as a local, per-project depen

MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way. ( WEBSITE VERSION )
MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query and get result in a fastest way. ( WEBSITE VERSION )

Mysql Optimizer mysql optimizer also known as MOP is a php query handling and manipulation library providing easy and reliable way to manipulate query

html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users

html-sanitizer html-sanitizer is a library aiming at handling, cleaning and sanitizing HTML sent by external users (who you cannot trust), allowing yo

A simple PHP library for handling Emoji

Emoji Emoji images from unicode characters and names (i.e. :sunrise:). Built to work with Twemoji images. use HeyUpdate\Emoji\Emoji; use HeyUpdate\Emo

PHP version of Google's phone number handling library

libphonenumber for PHP What is it? A PHP library for parsing, formatting, storing and validating international phone numbers. This library is based on

A simple PHP library for handling Emoji

Emoji Emoji images from unicode characters and names (i.e. :sunrise:). Built to work with Twemoji images. use HeyUpdate\Emoji\Emoji; use HeyUpdate\Emo

Firebird-PHP: A library created to meet a work need when handling a Firebird database
Firebird-PHP: A library created to meet a work need when handling a Firebird database

Firebird-PHP: A library created to meet a work need when handling a Firebird database

PHP library for handling sessions

Horizom Session PHP library for handling sessions. Requirements Installation Available Methods Quick Start Usage Tests TODO Changelog Contribution Spo

Receiver is a drop-in webhook handling library for Laravel.

Receiver Receiver is a drop-in webhook handling library for Laravel. Webhooks are a powerful part of any API lifecycle. Receiver aims to make handling

Owner
Jonathan Hanson
Jonathan Hanson
Library for converting units and sizes in PHP

php-conversion Library for converting units and sizes in PHP. Units supported Acceleration Angle Area Digital information Electric current Frequency F

Christoffer Niska 127 Dec 23, 2022
Library for converting units and sizes in PHP

php-conversion Library for converting units and sizes in PHP. Units supported Acceleration Angle Area Digital information Electric current Frequency F

Christoffer Niska 122 Mar 16, 2021
PHP version of Google's phone number handling library

libphonenumber for PHP What is it? A PHP library for parsing, formatting, storing and validating international phone numbers. This library is based on

Joshua Gigg 4.2k Jan 7, 2023
Mark Rogoyski 2.2k Dec 29, 2022
Tensor is a library and extension that provides objects for scientific computing in PHP.

Tensor is a library and extension that provides objects for scientific computing in PHP. The multithreaded extension is especially suited for computing large sets of numbers. In some cases, the extension is 230X faster than the same operation in PHPland. Tensor is used by libraries such as Rubix ML to build and accelerate machine learning algorithms such as linear regression, dimensionality reduction, and neural networks.

Rubix 157 Jan 3, 2023
A PHP 5.3+ mathematics library, providing functionality for large numbers

Moontoast Math Library Moontoast\Math is useful for working with integers that are larger than (or may become larger than, through mathematical comput

Moontoast 245 Sep 8, 2022
Advanced Mathematics Library for PHP (port of Numbers.js)

Numbers.php Numbers.php - an advanced mathematics toolkit for PHP >= 5.3. It is a port of Numbers.js - same toolkit for JavaScript. There is a version

null 159 Jul 24, 2022
BigNum library for PHP compatible with bn.js

BigNum library for PHP Information This library provides a PHP Big Number API compatible with bn.js and is used in Fast PHP ECC library elliptic-php.

Simplito 16 Nov 13, 2022
Arbitrary-precision arithmetic library for PHP

Arbitrary-precision arithmetic library for PHP

Brick 1.4k Jan 1, 2023
Unit converter and calculator for php

Unit converter and calculator This library uses the awesome lisachenko/z-engine to allow mathematical operations on objects, allowing to do stuff like

Dominik Chrástecký 8 Apr 8, 2022