├── .gitattributes ├── .github └── workflows │ └── ci.yaml ├── .gitignore ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── README.md ├── composer.json ├── scripts ├── lint ├── shell └── test ├── source ├── AbstractPhysicalQuantity.php ├── Exception │ ├── AbstractPhysicalQuantityException.php │ ├── DuplicateUnitNameOrAlias.php │ ├── NonNumericValue.php │ ├── NonStringUnitName.php │ ├── PhysicalQuantityMismatch.php │ └── UnknownUnitOfMeasure.php ├── HasSIUnitsTrait.php ├── PhysicalQuantity │ ├── Acceleration.php │ ├── Angle.php │ ├── Area.php │ ├── ElectricCurrent.php │ ├── Energy.php │ ├── Length.php │ ├── LuminousIntensity.php │ ├── Mass.php │ ├── Power.php │ ├── Pressure.php │ ├── Quantity.php │ ├── SolidAngle.php │ ├── Temperature.php │ ├── Time.php │ ├── Velocity.php │ └── Volume.php ├── PhysicalQuantityInterface.php ├── UnitOfMeasure.php └── UnitOfMeasureInterface.php └── tests ├── AbstractPhysicalQuantityTest.php ├── DemonstrationTests.php ├── Fixtures └── PhysicalQuantity │ ├── Wigginess.php │ ├── Wonkicity.php │ └── Woogosity.php ├── PhysicalQuantity ├── AbstractPhysicalQuantityTestCase.php ├── AccelerationTest.php ├── AngleTest.php ├── AreaTest.php ├── ElectricCurrentTest.php ├── EnergyTest.php ├── LengthTest.php ├── LuminousIntensityTest.php ├── MassTest.php ├── PowerTest.php ├── PressureTest.php ├── QuantityTest.php ├── SolidAngleTest.php ├── TemperatureTest.php ├── TimeTest.php ├── VelocityTest.php └── VolumeTest.php ├── UnitOfMeasureTest.php ├── phpcs.xml └── phpunit.xml.dist /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text eol=lf 3 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # .github/workflows/code_checks.yaml 2 | name: Code_Checks 3 | 4 | on: ["push", "pull_request"] 5 | 6 | jobs: 7 | tests: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | php: ['7.4'] 13 | stability: [ prefer-stable ] 14 | experimental: [false] 15 | include: 16 | - php: '7.4' 17 | stability: prefer-lowest 18 | - php: '8.0' 19 | - php: '8.1' 20 | - php: '8.2' 21 | - php: '8.3' 22 | - php: '8.4' 23 | 24 | name: PHP ${{ matrix.php }} - ${{ matrix.stability }} tests 25 | steps: 26 | # basically git clone 27 | - uses: actions/checkout@v4 28 | 29 | - name: Cache dependencies 30 | uses: actions/cache@v3 31 | with: 32 | path: ~/.composer/cache/files 33 | key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 34 | 35 | # use PHP of specific version 36 | - uses: shivammathur/setup-php@v2 37 | with: 38 | php-version: ${{ matrix.php }} 39 | extensions: pcov 40 | coverage: pcov 41 | 42 | - name: Install dependencies 43 | run: | 44 | composer install --verbose --prefer-dist --no-interaction -o 45 | 46 | - name: Execute tests 47 | run: composer run-script test 48 | 49 | cs: 50 | runs-on: ubuntu-latest 51 | steps: 52 | - uses: actions/checkout@v4 53 | - uses: shivammathur/setup-php@v2 54 | with: 55 | php-version: 8.2 56 | coverage: none # disable xdebug, pcov 57 | - run: composer install --no-progress 58 | - run: composer run-script lint 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editors and IDEs 2 | /.idea/ 3 | *.sublime-workspace 4 | *.sublime-project 5 | 6 | # Windows image file caches 7 | Thumbs.db 8 | 9 | # Mac folder view config 10 | .DS_Store 11 | Desktop.ini 12 | 13 | # Python compiled files 14 | *.py[co] 15 | 16 | # PHP Composer files 17 | /composer.phar 18 | /composer.lock 19 | /vendor/ 20 | 21 | # Sass 22 | ## From https://github.com/github/gitignore 23 | ### SASS Ignores - "Sassy CSS" http://sass-lang.com/ 24 | *.sass-cache 25 | 26 | .phpunit.result.cache 27 | tests/clover.xml 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v2.2.0 (April 30th, 2025) 2 | - Drop support of PHP < 7.4 3 | - Add `isUnitDefined()`, `listAllUnits()`, `getOriginalValue()`, and `getOriginalUnit()` methods to the Physical Quantity parent class 4 | - Add new Power Physical Quantity 5 | - Add Imperial Gallons to the Volume quantity 6 | - Move to Github Actions, away from Travis CI 7 | - Use Docker containers instead of Vagrant/VBox instances for dev environments 8 | - Add local dev scripts for `lint`, `test`, and `shell`, in `./scripts/` 9 | 10 | ## v2.1.0 (July 24th, 2016) 11 | - Added getUnitDefinitions() method to PhysicalQuantity classes, to get a raw list of UnitofMeasure objects defined on that quantity 12 | - Added UPPERCASE templating support for autogenerated metric units to support names like MEGA_METERS, for example. 13 | - New Quantity physical quantity, with `mole` as the standard unit, to represent the Amount of Substance SI base quantity. 14 | - New SolidAngle physical quantity, with `steradian` as the standard unit, to represent the solid angle quantity 15 | - Additional aliases for Area units 16 | - Additional units for time: decade, century, and millenium 17 | - Additional units for volume: teaspoon, tablespoon, gallon, quart, fluid ounce, and pint 18 | 19 | 20 | ## v2.0.1 (December 12th, 2015) 21 | - Migrated package from triplepoint/php-units-of-measure to php-units-of-measure/php-units-of-measure. 22 | - New physical quantity: Energy 23 | - New units of measure: 24 | - Area: are and decare 25 | - Length: nautical mile, mil, AU 26 | - Mass: stone, also slightly changed definitions of lb and oz 27 | - Time: yr, and jyr 28 | - Velocity: km/h, ft/s, mph, knot 29 | - Automated CI testing now includes HHVM and PHP 7 30 | - Removed the heavy vagrant git submodule, it was a silly thing. 31 | - Expanded the Readme for better contribution and installation instructions. 32 | 33 | ## v2.0.0 (March 14th, 2015) 34 | - Registered units of measure are now properties of PhysicalQuantity classes, and not individual instances of those classes. As such, registering a new unit with a given PhysicalQuantity will make that unit immediately available to all inntances of that class. 35 | - PhysicalQuantity classes no longer define their units in their constructor, and instead have a new initialize() static method 36 | - The previously-existing registerUnitOfMeasure() method on physical quantity objects has been replaced with a new static addUnit() method 37 | - The HasSoUnitsTrait method addMissingSIPrefixedUnits is now static 38 | - Added the toNativeUnit() method, to return values in their native unit of measure 39 | - Added the isEquivalentQuantity() method, to support future situations where it's not obvious whether two physical quantities represent the same quantity type 40 | - getSupportedUnits() is no longer available on physical quantities 41 | - The PhysicalQuantity parent class is now named AbstractPhysicalQuantity 42 | - Add a new DemonstrationTests test file, to demonstrate and test typical use cases 43 | - All library exceptions extend from AbstractPhysicalQuantityException, making catching easier 44 | - Added an interface for PhysicalQuantities, to support future work where not all physical quantity classes necessarily have the same parent 45 | 46 | ## v1.3.3 (March 15th, 2015) 47 | - Loosened Composer requirement on PHP version to >=5.3.0 (was previously 5.3.5). 48 | 49 | ## v1.3.1 (August 23rd, 2014) 50 | - Added information in the README about the new SI prefix units generation 51 | 52 | ## v1.3.0 (August 23rd, 2014) 53 | - Add support for automatically generating metric-prefixed units from a single base unit 54 | - Throw an exception on registering units of measure with names or aliases that collide with existing units on that quantity 55 | - Disallow values that aren't numerical and unit names that aren't strings (ie, type checking) 56 | - Add new method getSupportedUnits() to Physical Quantities 57 | - Add new method getAliases() to Units of Measure 58 | - Add arcminute and arcsecond as angle units 59 | - Add all SI prefix units to meters, kilograms, seconds, amps, kelvin, candela, pascal, bar, radians, degrees, and arcseconds 60 | 61 | ## v1.2.0 (August 16th, 2014) 62 | - Drop support for PHP 5.3 63 | - Moved to PSR-4 namespace convention 64 | - Drop support for an array of names passed in the constructor as a way to specify aliases for UnitOfMeasure objects; addAlias() now required. 65 | - Add UnitOfMeasure::nativeUnitFactory() and UnitOfMeasure::linearUnitFactory() convenience factory methods 66 | - Add optional spelling for 'metres' and 'litres' 67 | - Add Vagrant-based testing virtual machine, for convenience 68 | 69 | ## v1.1.2 (February 9th, 2014) 70 | - New units of measure on Area: hectares, international acres 71 | - New units of measure on Temperature: Rankin, Delisle, Newton, Réaumur, Rømer 72 | - Improved unit test coverage 73 | 74 | ## v1.1.1 (July 8th, 2013) 75 | - New physical quantity: Angle 76 | - Additional units of measure on Time 77 | 78 | ## v1.1.0 (May 7th, 2013) 79 | - Add add() and subtract() methods to physical quantities 80 | - toString() on quantities now shows the original unit, as expected 81 | 82 | ## v1.0.0 (May 7th, 2013) 83 | Initial Commit 84 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4-cli 2 | 3 | RUN apt-get update && apt-get install -y --no-install-recommends \ 4 | git \ 5 | curl \ 6 | unzip \ 7 | && rm -rf /var/lib/apt/lists/* 8 | 9 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin && ln -s /usr/local/bin/composer.phar /usr/local/bin/composer 10 | 11 | RUN git config --global --add safe.directory /project 12 | 13 | WORKDIR /project 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012 Jonathan Hanson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Units of Measure 2 | master: [![Build Status](https://travis-ci.org/PhpUnitsOfMeasure/php-units-of-measure.png?branch=master)](https://travis-ci.org/PhpUnitsOfMeasure/php-units-of-measure) 3 | 4 | ## Introduction 5 | 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: 6 | 7 | ``` php 8 | use PhpUnitsOfMeasure\PhysicalQuantity\Length; 9 | 10 | $height = new Length(6.16, 'feet'); 11 | echo $height->toUnit('m'); 12 | 13 | // would print 1.87757, which is 6.16 feet in meters. 14 | ``` 15 | 16 | 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: 17 | 18 | ``` php 19 | // Tied to a specific unit of measure 20 | function isTooTallToRideThisTrain( $height ) 21 | { 22 | return $height > 5; 23 | } 24 | 25 | // Calling the function requires that you first convert whatever quantity 26 | // you have into the expected units: 27 | isTooTallToRideThisTrain(2 / 0.3048); 28 | ``` 29 | 30 | Whereas this version using this library allows for height to be provided in whatever unit is convenient: 31 | 32 | ``` php 33 | use PhpUnitsOfMeasure\PhysicalQuantity\Length; 34 | 35 | // Free to operate on lengths in any unit of measure 36 | function isTooTallToRideThisTrain( Length $height ) 37 | { 38 | return $height->toUnit('ft') > 5; 39 | } 40 | 41 | // Calling the function now allows any unit to be used: 42 | isTooTallToRideThisTrain( new Length(2, 'm') ); 43 | ``` 44 | 45 | ## Installation 46 | This library is best included in your projects via Composer. See the [Composer website](https://getcomposer.org/) for more details, and see the [Packagist.org site for this library](https://packagist.org/packages/php-units-of-measure/php-units-of-measure). 47 | 48 | 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](https://www.php-fig.org/psr/psr-4/) compliant PHP autoloader. The mapping between this project's root namespace and its base directory is: 49 | - vendor namespace 'PhpUnitsOfMeasure\' maps to the library's base directory 'source/' 50 | 51 | See the documentation of your autoloader for further instructions. 52 | 53 | ### Project Tags and Versions 54 | This project follows the guidelines set out in [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html). In general, versions are of the form 'X.Y.Z', and increments to X denote backward-incompatible major changes. 55 | 56 | 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](https://getcomposer.org/), 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. 57 | 58 | 59 | ## Use 60 | ### Conversion 61 | 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: 62 | 63 | ``` php 64 | use PhpUnitsOfMeasure\PhysicalQuantity\Mass; 65 | 66 | $quantity = new Mass(6, 'lbs'); 67 | echo $quantity->toUnit('g'); 68 | ``` 69 | It's also possible to implicity cast a quantity to a string, which will display its original value: 70 | 71 | ``` php 72 | use PhpUnitsOfMeasure\PhysicalQuantity\Mass; 73 | 74 | $quantity = new Mass(6, 'pounds'); 75 | echo $quantity; // '6 lbs' 76 | ``` 77 | 78 | ### Arithmetic Operators 79 | 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: 80 | 81 | ``` php 82 | use PhpUnitsOfMeasure\PhysicalQuantity\Volume; 83 | 84 | $first = new Volume(6, 'liters'); 85 | $second = new Volume(6, 'cups'); 86 | 87 | $sum = $first->add($second); 88 | echo $sum; // 7.4195292 l 89 | 90 | $difference = $first->subtract($second); 91 | echo $difference; // 4.5804708 l 92 | ``` 93 | 94 | ### Adding new Units of Measure to Existing Quantities 95 | Ocassionally, you will need to add a new unit of measure to a pre-existing quantity. 96 | 97 | 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. 98 | 99 | #### Adding a New Unit of Measure at Runtime 100 | To add a new unit of measure to an existing quantity at run time, you'd do this: 101 | 102 | ``` php 103 | use PhpUnitsOfMeasure\PhysicalQuantity\Length; 104 | use PhpUnitsOfMeasure\PhysicalQuantity\UnitOfMeasure; 105 | 106 | // It's ok to create objects with cubits before the new unit is registered, since 107 | // the conversion doesn't happen until an output method is called 108 | $length = new Length(14, 'cubits'); 109 | 110 | // Build a new Unit of Measure object which represents the new unit, and which 111 | // knows how to convert between the new unit and the quantity's native unit 112 | // (in this case, meters). 113 | $cubit = new UnitOfMeasure( 114 | 115 | // This is the official name of this unit - typically it's the standard 116 | // abbreviation 117 | 'cb', 118 | 119 | // The second parameter is a function that converts from the native unit 120 | // to this unit 121 | function ($valueInNativeUnit) { 122 | return $valueInNativeUnit / 0.4572; 123 | }, 124 | 125 | // The third parameter is a function that converts from this unit to the 126 | // native unit 127 | function ($valueInThisUnit) { 128 | return $valueInThisUnit * 0.4572; 129 | } 130 | ); 131 | 132 | // Any alias names for this unit can be added here, to make it easier to use 133 | // variations 134 | $cubit->addAlias('cubit'); 135 | $cubit->addAlias('cubits'); 136 | 137 | // Register the new unit of measure with the quantity class 138 | Length::addUnit($cubit); 139 | 140 | // Now that the unit is registered, you can cast the measurement to any other 141 | // measure of length 142 | echo $length->toUnit('feet'); // '21' 143 | ``` 144 | 145 | ##### Shorthand Factory Methods 146 | 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. 147 | 148 | ``` php 149 | $megameter = UnitOfMeasure::linearUnitFactory('Mm', 1e6); 150 | $megameter->addAlias('Megameter'); 151 | $megameter->addAlias('Megametre'); 152 | Length::addUnit($megameter); 153 | ``` 154 | 155 | 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: 156 | 157 | ``` php 158 | $meter = UnitOfMeasure::nativeUnitFactory('m'); 159 | $meter->addAlias('meter'); 160 | $meter->addAlias('metre'); 161 | Length::addUnit($meter); 162 | ``` 163 | 164 | ##### Automatically Generating Metric Units 165 | For units that use the metric system, there's a convenience trait available for classes which implement`PhysicalQuantityInterface` which will automatically generate the full continuum of metric units from a single unit. For instance: 166 | 167 | ``` php 168 | namespace PhpUnitsOfMeasure\PhysicalQuantity; 169 | 170 | use PhpUnitsOfMeasure\AbstractPhysicalQuantity; 171 | use PhpUnitsOfMeasure\UnitOfMeasure; 172 | use PhpUnitsOfMeasure\HasSIUnitsTrait; 173 | 174 | class Mass extends AbstractPhysicalQuantity 175 | { 176 | use HasSIUnitsTrait; 177 | 178 | protected static $unitDefinitions; 179 | 180 | protected static function initialize() 181 | { 182 | // Kilogram 183 | $kilogram = UnitOfMeasure::nativeUnitFactory('kg'); 184 | $kilogram->addAlias('kilogram'); 185 | $kilogram->addAlias('kilograms'); 186 | static::addUnit($kilogram); 187 | 188 | static::addMissingSIPrefixedUnits( 189 | $kilogram, 190 | 1e-3, 191 | '%pg', 192 | [ 193 | '%Pgram', 194 | '%Pgrams', 195 | ] 196 | ); 197 | } 198 | } 199 | ``` 200 | 201 | 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. 202 | 203 | 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. 204 | 205 | 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', ...` . 206 | 207 | #### Permanently Adding a New Unit of Measure to a Physical Quantity 208 | 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. 209 | 210 | 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: 211 | 212 | ``` php 213 | namespace PhpUnitsOfMeasure\PhysicalQuantity; 214 | 215 | use PhpUnitsOfMeasure\AbstractPhysicalQuantity; 216 | use PhpUnitsOfMeasure\UnitOfMeasure; 217 | 218 | class Length extends AbstractPhysicalQuantity 219 | { 220 | protected static $unitDefinitions; 221 | 222 | protected static function initialize() 223 | { 224 | // ... 225 | // ... 226 | // Here's all the pre-existing unit definitions for Length 227 | // ... 228 | // ... 229 | 230 | // Cubit 231 | $cubit = UnitOfMeasure::linearUnitFactory('cb', 0.4572); 232 | $cubit->addAlias('cubit'); 233 | $cubit->addAlias('cubits'); 234 | static::addUnit($cubit); 235 | } 236 | } 237 | ``` 238 | 239 | 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. 240 | 241 | ### Adding New Physical Quantities 242 | [Physical quantities](https://en.wikipedia.org/wiki/Physical_quantity) are categories of measurable values, like mass, length, force, etc. 243 | 244 | 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. 245 | 246 | 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. 247 | 248 | ### Adding new Aliases to Existing Units 249 | 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: 250 | 251 | ``` php 252 | use PhpUnitsOfMeasure\PhysicalQuantity\Length; 253 | 254 | // It's ok to use footses here, since the conversion doesn't happen 255 | // until later 256 | $length = new Length(4, 'footses'); 257 | 258 | // Fetch the unit of measure object that represents the 'ft' unit 259 | $footUnit = Length::getUnit('ft'); 260 | 261 | // Any alias names for this unit can be added here, to make it easier 262 | // to use variations 263 | $footUnit->addAlias('footses'); 264 | 265 | // Now that the unit has been modified with its new alias, you can cast 266 | // the measurement to any other measure of length 267 | echo $length->toUnit('m'); // '1.2192' 268 | ``` 269 | 270 | 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. 271 | 272 | ## Testing and Contributing 273 | 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. 274 | 275 | 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"](http://www.nist.gov/pml/wmd/metric/upload/SP1038.pdf). This guide contains the approved conversion factors between various units and the base SI units. 276 | 277 | Also note that any new physical quantities should have the appropriate SI unit chosen for their native unit of measure. 278 | 279 | ### Pull Requests and Merging 280 | The workflow for this repository goes as follows: 281 | - To develop new contributions, fork or branch from the `master` branch of the main repository 282 | - Pull requests and contribution merges are always made to the `master` branch of the main repository 283 | - From time to time, commits of `master` are tagged and a new version is released 284 | - 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. 285 | 286 | 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. 287 | 288 | ### Local Testing Environment 289 | There's a `Dockerfile` and a set of helper scripts in `scripts/` suitable for running the necessary unit tests. With Docker installed, do: 290 | 291 | ``` shell 292 | # Execute the lint checks 293 | ./script/lint 294 | 295 | # Execute the unit tests 296 | ./script/test 297 | ``` 298 | 299 | In addition, `./script/shell` will get you a bash shell in a temporary container. Note that the hosts directory is mounted into the container, and changes to files inside the container will persist. 300 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "php-units-of-measure/php-units-of-measure", 3 | "description": "A PHP library for converting between standard units of measure.", 4 | "keywords": [ 5 | "measurements", 6 | "data", 7 | "conversion" 8 | ], 9 | "homepage": "https://github.com/PhpUnitsOfMeasure/php-units-of-measure", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Jonathan Hanson", 14 | "role": "Developer" 15 | } 16 | ], 17 | "support": { 18 | "issues": "https://github.com/PhpUnitsOfMeasure/php-units-of-measure/issues", 19 | "source": "https://github.com/PhpUnitsOfMeasure/php-units-of-measure" 20 | }, 21 | "require": { 22 | "php": ">=7.4" 23 | }, 24 | "require-dev": { 25 | "phpunit/phpunit": "^9.5", 26 | "squizlabs/php_codesniffer": "^3.7" 27 | }, 28 | "replace": { 29 | "triplepoint/php-units-of-measure": "*" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "PhpUnitsOfMeasure\\": "source/" 34 | } 35 | }, 36 | "autoload-dev": { 37 | "psr-4": { 38 | "PhpUnitsOfMeasureTest\\": "tests/" 39 | } 40 | }, 41 | "scripts": { 42 | "test": "phpunit -c ./tests/phpunit.xml.dist ./tests", 43 | "lint": "phpcs --encoding=utf-8 --extensions=php --standard=./tests/phpcs.xml -nsp ./" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /scripts/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | docker build -t "php-units-of-measure:dev" . 5 | docker run -it --rm -v `pwd`:/project "php-units-of-measure:dev" composer run-script lint 6 | -------------------------------------------------------------------------------- /scripts/shell: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | docker build -t "php-units-of-measure:dev" . 5 | docker run -it --rm -v `pwd`:/project "php-units-of-measure:dev" bash 6 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | docker build -t "php-units-of-measure:dev" . 5 | docker run -it --rm -v `pwd`:/project "php-units-of-measure:dev" composer run-script test 6 | -------------------------------------------------------------------------------- /source/AbstractPhysicalQuantity.php: -------------------------------------------------------------------------------- 1 | implode(', ', array_merge([$unit->getName()], $unit->getAliases())) 44 | ]); 45 | } 46 | 47 | static::$unitDefinitions[] = $unit; 48 | } 49 | 50 | /** 51 | * Get the unit of measure that matches the given name by either name or alias. 52 | * 53 | * @param string $unit A name or alias by which the unit is known. 54 | * 55 | * @throws Exception\UnknownUnitOfMeasure when an unknown unit of measure is given 56 | * 57 | * @return UnitOfMeasureInterface 58 | */ 59 | public static function getUnit($unit) 60 | { 61 | // If this class hasn't been initialized yet, do so now 62 | if (!is_array(static::$unitDefinitions)) { 63 | static::$unitDefinitions = []; 64 | static::initialize(); 65 | } 66 | 67 | $key = static::buildUnitCacheKey($unit); 68 | if (isset(self::$unitCache[$key])) { 69 | return self::$unitCache[$key]; 70 | } 71 | 72 | foreach (static::$unitDefinitions as $unitOfMeasure) { 73 | if ($unit === $unitOfMeasure->getName() || $unitOfMeasure->isAliasOf($unit)) { 74 | return self::$unitCache[$key] = $unitOfMeasure; 75 | } 76 | } 77 | 78 | throw new Exception\UnknownUnitOfMeasure([':unit' => $unit]); 79 | } 80 | 81 | /** 82 | * Given a unit of measure, determine if its name or any of its aliases conflict 83 | * with the set of already-known unit names and aliases. 84 | * 85 | * @param UnitOfMeasureInterface $unit The unit in question 86 | * 87 | * @return boolean true if there is a conflict, false if there is not 88 | */ 89 | protected static function unitNameOrAliasesAlreadyRegistered(UnitOfMeasureInterface $unit) 90 | { 91 | // If this class hasn't been initialized yet, do so now 92 | if (!is_array(static::$unitDefinitions)) { 93 | static::$unitDefinitions = []; 94 | static::initialize(); 95 | } 96 | 97 | $currentUnitNamesAndAliases = []; 98 | foreach (static::$unitDefinitions as $unitOfMeasure) { 99 | $currentUnitNamesAndAliases[] = $unitOfMeasure->getName(); 100 | $currentUnitNamesAndAliases = array_merge($currentUnitNamesAndAliases, $unitOfMeasure->getAliases()); 101 | } 102 | 103 | $newUnitNamesAndAliases = array_merge([$unit->getName()], $unit->getAliases()); 104 | 105 | return count(array_intersect($currentUnitNamesAndAliases, $newUnitNamesAndAliases)) > 0; 106 | } 107 | 108 | /** 109 | * Initialize the static properties of this quantity class, such as the set of 110 | * default units of measure. 111 | */ 112 | protected static function initialize() 113 | { 114 | } 115 | 116 | 117 | /** 118 | * The scalar value, in the original unit of measure. 119 | * 120 | * @var float 121 | */ 122 | protected $originalValue; 123 | 124 | /** 125 | * The original unit of measure's string representation. 126 | * 127 | * @var string 128 | */ 129 | protected $originalUnit; 130 | 131 | /** 132 | * Store the value and its original unit. 133 | * 134 | * @param float $value The scalar value of the measurement 135 | * @param string $unit The unit of measure in which this value is provided 136 | * 137 | * @throws Exception\NonNumericValue If the value is not numeric 138 | * @throws Exception\NonStringUnitName If the unit is not a string 139 | */ 140 | public function __construct($value, $unit) 141 | { 142 | if (!is_numeric($value)) { 143 | throw new Exception\NonNumericValue([':value' => $value]); 144 | } 145 | 146 | if (!is_string($unit)) { 147 | throw new Exception\NonStringUnitName([':name' => $unit]); 148 | } 149 | 150 | $this->originalValue = $value; 151 | $this->originalUnit = $unit; 152 | } 153 | 154 | /** 155 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::toUnit 156 | */ 157 | public function toUnit($toUnit) 158 | { 159 | return $this->toUnitOfMeasure(static::getUnit($toUnit)); 160 | } 161 | 162 | /** 163 | * Convert this quantity to the given unit of measure. 164 | * 165 | * @param UnitOfMeasureInterface $unit The object representing the target unit of measure. 166 | * 167 | * @return float This quantity's value in the given unit of measure. 168 | */ 169 | private function toUnitOfMeasure(UnitOfMeasureInterface $unit) 170 | { 171 | $thisValueInNativeUnit = $this->toNativeUnit(); 172 | return $unit->convertValueFromNativeUnitOfMeasure($thisValueInNativeUnit); 173 | } 174 | 175 | /** 176 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::toNativeUnit 177 | */ 178 | public function toNativeUnit() 179 | { 180 | return static::getUnit($this->originalUnit) 181 | ->convertValueToNativeUnitOfMeasure($this->originalValue); 182 | } 183 | 184 | /** 185 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::__toString 186 | */ 187 | public function __toString() 188 | { 189 | return trim($this->originalValue . ' ' . static::getUnit($this->originalUnit)->getName()); 190 | } 191 | 192 | /** 193 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::add 194 | */ 195 | public function add(PhysicalQuantityInterface $quantity) 196 | { 197 | if (!$this->isEquivalentQuantity($quantity)) { 198 | throw new Exception\PhysicalQuantityMismatch([ 199 | ':lhs' => (string) $this, 200 | ':rhs' => (string) $quantity 201 | ]); 202 | } 203 | 204 | $quantityValueInThisOriginalUnit = $quantity->toUnitOfMeasure(static::getUnit($this->originalUnit)); 205 | $newValue = $this->originalValue + $quantityValueInThisOriginalUnit; 206 | 207 | return new static($newValue, static::getUnit($this->originalUnit)->getName()); 208 | } 209 | 210 | /** 211 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::subtract 212 | */ 213 | public function subtract(PhysicalQuantityInterface $quantity) 214 | { 215 | if (!$this->isEquivalentQuantity($quantity)) { 216 | throw new Exception\PhysicalQuantityMismatch([ 217 | ':lhs' => (string) $this, 218 | ':rhs' => (string) $quantity 219 | ]); 220 | } 221 | 222 | $quantityValueInThisOriginalUnit = $quantity->toUnitOfMeasure(static::getUnit($this->originalUnit)); 223 | $newValue = $this->originalValue - $quantityValueInThisOriginalUnit; 224 | 225 | return new static($newValue, static::getUnit($this->originalUnit)->getName()); 226 | } 227 | 228 | /** 229 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::isEquivalentQuantity 230 | */ 231 | public function isEquivalentQuantity(PhysicalQuantityInterface $testQuantity) 232 | { 233 | return get_class($this) === get_class($testQuantity); 234 | } 235 | 236 | /** 237 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::isUnitDefined 238 | */ 239 | public static function isUnitDefined($name) 240 | { 241 | $units = static::getUnitDefinitions(); 242 | foreach ($units as $unit) { 243 | if ($name === $unit->getName() || $unit->isAliasOf($name)) { 244 | return true; 245 | } 246 | } 247 | return false; 248 | } 249 | 250 | /** 251 | * @see \PhpUnitsOfMeasure\PhysicalQuantityInterface::listAllUnits 252 | */ 253 | public static function listAllUnits() 254 | { 255 | $return = []; 256 | $units = static::getUnitDefinitions(); 257 | foreach ($units as $unit) { 258 | $return[$unit->getName()] = $unit->getAliases(); 259 | } 260 | return $return; 261 | } 262 | 263 | /** 264 | * Get the unit definition array 265 | * @return Array $unitDefinitions 266 | */ 267 | public static function getUnitDefinitions() 268 | { 269 | if (!is_array(static::$unitDefinitions)) { 270 | static::$unitDefinitions = []; 271 | static::initialize(); 272 | } 273 | 274 | return static::$unitDefinitions; 275 | } 276 | 277 | /** 278 | * @return float 279 | */ 280 | public function getOriginalValue() 281 | { 282 | return $this->originalValue; 283 | } 284 | 285 | /** 286 | * @return string 287 | */ 288 | public function getOriginalUnit() 289 | { 290 | return $this->originalUnit; 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /source/Exception/AbstractPhysicalQuantityException.php: -------------------------------------------------------------------------------- 1 | error, $parameters); 24 | parent::__construct($message); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /source/Exception/DuplicateUnitNameOrAlias.php: -------------------------------------------------------------------------------- 1 | 'Y', 52 | 'long_prefix' => 'yotta', 53 | 'factor' => 1e24 54 | ], 55 | [ 56 | 'abbr_prefix' => 'Z', 57 | 'long_prefix' => 'zetta', 58 | 'factor' => 1e21 59 | ], 60 | [ 61 | 'abbr_prefix' => 'E', 62 | 'long_prefix' => 'exa', 63 | 'factor' => 1e18 64 | ], 65 | [ 66 | 'abbr_prefix' => 'P', 67 | 'long_prefix' => 'peta', 68 | 'factor' => 1e15 69 | ], 70 | [ 71 | 'abbr_prefix' => 'T', 72 | 'long_prefix' => 'tera', 73 | 'factor' => 1e12 74 | ], 75 | [ 76 | 'abbr_prefix' => 'G', 77 | 'long_prefix' => 'giga', 78 | 'factor' => 1e9 79 | ], 80 | [ 81 | 'abbr_prefix' => 'M', 82 | 'long_prefix' => 'mega', 83 | 'factor' => 1e6 84 | ], 85 | [ 86 | 'abbr_prefix' => 'k', 87 | 'long_prefix' => 'kilo', 88 | 'factor' => 1e3 89 | ], 90 | [ 91 | 'abbr_prefix' => 'h', 92 | 'long_prefix' => 'hecto', 93 | 'factor' => 1e2 94 | ], 95 | [ 96 | 'abbr_prefix' => 'da', 97 | 'long_prefix' => 'deca', 98 | 'factor' => 1e1 99 | ], 100 | [ 101 | 'abbr_prefix' => '', 102 | 'long_prefix' => '', 103 | 'factor' => 1 104 | ], 105 | [ 106 | 'abbr_prefix' => 'd', 107 | 'long_prefix' => 'deci', 108 | 'factor' => 1e-1 109 | ], 110 | [ 111 | 'abbr_prefix' => 'c', 112 | 'long_prefix' => 'centi', 113 | 'factor' => 1e-2 114 | ], 115 | [ 116 | 'abbr_prefix' => 'm', 117 | 'long_prefix' => 'milli', 118 | 'factor' => 1e-3 119 | ], 120 | [ 121 | 'abbr_prefix' => 'µ', 122 | 'long_prefix' => 'micro', 123 | 'factor' => 1e-6 124 | ], 125 | [ 126 | 'abbr_prefix' => 'n', 127 | 'long_prefix' => 'nano', 128 | 'factor' => 1e-9 129 | ], 130 | [ 131 | 'abbr_prefix' => 'p', 132 | 'long_prefix' => 'pico', 133 | 'factor' => 1e-12 134 | ], 135 | [ 136 | 'abbr_prefix' => 'f', 137 | 'long_prefix' => 'femto', 138 | 'factor' => 1e-15 139 | ], 140 | [ 141 | 'abbr_prefix' => 'a', 142 | 'long_prefix' => 'atto', 143 | 'factor' => 1e-18 144 | ], 145 | [ 146 | 'abbr_prefix' => 'z', 147 | 'long_prefix' => 'zepto', 148 | 'factor' => 1e-21 149 | ], 150 | [ 151 | 'abbr_prefix' => 'y', 152 | 'long_prefix' => 'yocto', 153 | 'factor' => 1e-24 154 | ], 155 | ]; 156 | 157 | // Determine the conversion factor from the no-prefix SI unit to the physical quantity's native unit 158 | $noPrefixToNativeUnitFactor = $siUnit->convertValueToNativeUnitOfMeasure(1) * $toBaseSiUnitFactor; 159 | 160 | // For each of the standard SI prefixes, attempt to register a new unit of measure 161 | foreach ($siPrefixes as $prefixDefinition) { 162 | // Build a function for resolving a pattern into a unit name 163 | $parsePattern = function ($pattern) use ($prefixDefinition) { 164 | return strtr( 165 | $pattern, 166 | [ 167 | '%p' => $prefixDefinition['abbr_prefix'], 168 | '%P' => $prefixDefinition['long_prefix'], 169 | '%U' => strtoupper($prefixDefinition['long_prefix']) 170 | ] 171 | ); 172 | }; 173 | 174 | // Generate the base name of the new unit 175 | $name = $parsePattern($namePattern); 176 | 177 | // Determine the factor that converts the new unit into the physical quantity's 178 | // native unit of measure. 179 | $toNativeUnitFactor = $noPrefixToNativeUnitFactor * $prefixDefinition['factor']; 180 | 181 | // Instantiate the new unit of measure 182 | $newUnit = UnitOfMeasure::linearUnitFactory($name, $toNativeUnitFactor); 183 | 184 | // Generate the aliases of the new unit 185 | foreach ($aliasPatterns as $aliasPattern) { 186 | $newUnitAlias = $parsePattern($aliasPattern); 187 | $newUnit->addAlias($newUnitAlias); 188 | } 189 | 190 | // If the unit doesn't conflict with any of the already-existing units, register it 191 | if (!static::unitNameOrAliasesAlreadyRegistered($newUnit)) { 192 | static::addUnit($newUnit); 193 | } 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Acceleration.php: -------------------------------------------------------------------------------- 1 | addAlias('m/s²'); 16 | $meterpersecondsquared->addAlias('meter per second squared'); 17 | $meterpersecondsquared->addAlias('meters per second squared'); 18 | $meterpersecondsquared->addAlias('metre per second squared'); 19 | $meterpersecondsquared->addAlias('metres per second squared'); 20 | static::addUnit($meterpersecondsquared); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Angle.php: -------------------------------------------------------------------------------- 1 | addAlias('radian'); 19 | $radian->addAlias('radians'); 20 | static::addUnit($radian); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $radian, 24 | 1, 25 | '%prad', 26 | [ 27 | '%Pradian', 28 | '%Pradians', 29 | ] 30 | ); 31 | 32 | // Degrees 33 | $degree = UnitOfMeasure::linearUnitFactory('deg', M_PI / 180); 34 | $degree->addAlias('°'); 35 | $degree->addAlias('degree'); 36 | $degree->addAlias('degrees'); 37 | static::addUnit($degree); 38 | 39 | static::addMissingSIPrefixedUnits( 40 | $degree, 41 | 1, 42 | '%pdeg', 43 | [ 44 | '%Pdegree', 45 | '%Pdegrees', 46 | ] 47 | ); 48 | 49 | // Arcminute 50 | $arcminute = UnitOfMeasure::linearUnitFactory('arcmin', M_PI / 180 / 60); 51 | $arcminute->addAlias('′'); 52 | $arcminute->addAlias('arcminute'); 53 | $arcminute->addAlias('arcminutes'); 54 | $arcminute->addAlias('amin'); 55 | $arcminute->addAlias('am'); 56 | $arcminute->addAlias('MOA'); 57 | static::addUnit($arcminute); 58 | 59 | // Arcsecond 60 | $arcsecond = UnitOfMeasure::linearUnitFactory('arcsec', M_PI / 180 / 3600); 61 | $arcsecond->addAlias('″'); 62 | $arcminute->addAlias('arcsecond'); 63 | $arcminute->addAlias('arcseconds'); 64 | $arcsecond->addAlias('asec'); 65 | $arcsecond->addAlias('as'); 66 | static::addUnit($arcsecond); 67 | 68 | static::addMissingSIPrefixedUnits( 69 | $arcsecond, 70 | 1, 71 | '%Parcsec', 72 | [ 73 | '%Parcsecond', 74 | '%Parcseconds', 75 | '%pasec', 76 | '%pas', 77 | ] 78 | ); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Area.php: -------------------------------------------------------------------------------- 1 | addAlias('m²'); 16 | $metersquared->addAlias('meter squared'); 17 | $metersquared->addAlias('square meter'); 18 | $metersquared->addAlias('square meters'); 19 | $metersquared->addAlias('meters squared'); 20 | $metersquared->addAlias('metre squared'); 21 | $metersquared->addAlias('metres squared'); 22 | static::addUnit($metersquared); 23 | 24 | // Millimeter squared 25 | $newUnit = UnitOfMeasure::linearUnitFactory('mm^2', 1e-6); 26 | $newUnit->addAlias('mm²'); 27 | $newUnit->addAlias('millimeter squared'); 28 | $newUnit->addAlias('square millimeter'); 29 | $newUnit->addAlias('square millimeters'); 30 | $newUnit->addAlias('millimeters squared'); 31 | $newUnit->addAlias('millimetre squared'); 32 | $newUnit->addAlias('millimetres squared'); 33 | static::addUnit($newUnit); 34 | 35 | // Centimeter squared 36 | $newUnit = UnitOfMeasure::linearUnitFactory('cm^2', 1e-4); 37 | $newUnit->addAlias('cm²'); 38 | $newUnit->addAlias('centimeter squared'); 39 | $newUnit->addAlias('square centimeter'); 40 | $newUnit->addAlias('square centimeters'); 41 | $newUnit->addAlias('centimeters squared'); 42 | $newUnit->addAlias('centimetre squared'); 43 | $newUnit->addAlias('centimetres squared'); 44 | static::addUnit($newUnit); 45 | 46 | // Decimeter squared 47 | $newUnit = UnitOfMeasure::linearUnitFactory('dm^2', 1e-2); 48 | $newUnit->addAlias('dm²'); 49 | $newUnit->addAlias('decimeter squared'); 50 | $newUnit->addAlias('square decimeters'); 51 | $newUnit->addAlias('square decimeter'); 52 | $newUnit->addAlias('decimeters squared'); 53 | $newUnit->addAlias('decimetre squared'); 54 | $newUnit->addAlias('decimetres squared'); 55 | static::addUnit($newUnit); 56 | 57 | // Kilometer squared 58 | $newUnit = UnitOfMeasure::linearUnitFactory('km^2', 1e6); 59 | $newUnit->addAlias('km²'); 60 | $newUnit->addAlias('kilometer squared'); 61 | $newUnit->addAlias('kilometers squared'); 62 | $newUnit->addAlias('square kilometer'); 63 | $newUnit->addAlias('square kilometers'); 64 | $newUnit->addAlias('kilometre squared'); 65 | $newUnit->addAlias('kilometres squared'); 66 | static::addUnit($newUnit); 67 | 68 | // Foot squared 69 | $newUnit = UnitOfMeasure::linearUnitFactory('ft^2', 9.290304e-2); 70 | $newUnit->addAlias('ft²'); 71 | $newUnit->addAlias('foot squared'); 72 | $newUnit->addAlias('square foot'); 73 | $newUnit->addAlias('square feet'); 74 | $newUnit->addAlias('feet squared'); 75 | static::addUnit($newUnit); 76 | 77 | // Inch squared 78 | $newUnit = UnitOfMeasure::linearUnitFactory('in^2', 6.4516e-4); 79 | $newUnit->addAlias('in²'); 80 | $newUnit->addAlias('inch squared'); 81 | $newUnit->addAlias('square inch'); 82 | $newUnit->addAlias('square inches'); 83 | $newUnit->addAlias('inches squared'); 84 | static::addUnit($newUnit); 85 | 86 | // Mile squared 87 | $newUnit = UnitOfMeasure::linearUnitFactory('mi^2', 2.589988e6); 88 | $newUnit->addAlias('mi²'); 89 | $newUnit->addAlias('mile squared'); 90 | $newUnit->addAlias('miles squared'); 91 | $newUnit->addAlias('square mile'); 92 | $newUnit->addAlias('square miles'); 93 | static::addUnit($newUnit); 94 | 95 | // Yard squared 96 | $newUnit = UnitOfMeasure::linearUnitFactory('yd^2', 8.361274e-1); 97 | $newUnit->addAlias('yd²'); 98 | $newUnit->addAlias('yard squared'); 99 | $newUnit->addAlias('yards squared'); 100 | $newUnit->addAlias('square yard'); 101 | $newUnit->addAlias('square yards'); 102 | static::addUnit($newUnit); 103 | 104 | // Are 105 | $newUnit = UnitOfMeasure::linearUnitFactory('a', 100); 106 | $newUnit->addAlias('are'); 107 | $newUnit->addAlias('ares'); 108 | static::addUnit($newUnit); 109 | 110 | // Decare 111 | $newUnit = UnitOfMeasure::linearUnitFactory('daa', 1000); 112 | $newUnit->addAlias('decare'); 113 | $newUnit->addAlias('decares'); 114 | static::addUnit($newUnit); 115 | 116 | // Hectare 117 | $newUnit = UnitOfMeasure::linearUnitFactory('ha', 10000); 118 | $newUnit->addAlias('hectare'); 119 | $newUnit->addAlias('hectares'); 120 | static::addUnit($newUnit); 121 | 122 | // International Acre 123 | $newUnit = UnitOfMeasure::linearUnitFactory('ac', 4046.8564224); 124 | $newUnit->addAlias('acre'); 125 | $newUnit->addAlias('acres'); 126 | static::addUnit($newUnit); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/ElectricCurrent.php: -------------------------------------------------------------------------------- 1 | addAlias('amp'); 19 | $ampere->addAlias('amps'); 20 | $ampere->addAlias('ampere'); 21 | $ampere->addAlias('amperes'); 22 | static::addUnit($ampere); 23 | 24 | static::addMissingSIPrefixedUnits( 25 | $ampere, 26 | 1, 27 | '%pA', 28 | [ 29 | '%Pamp', 30 | '%Pamps', 31 | '%Pampere', 32 | '%Pamperes' 33 | ] 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Energy.php: -------------------------------------------------------------------------------- 1 | addAlias('joule'); 19 | $joule->addAlias('joules'); 20 | static::addUnit($joule); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $joule, 24 | 1, 25 | '%pJ', 26 | [ 27 | '%Pjoule', 28 | '%Pjoules', 29 | ] 30 | ); 31 | 32 | // Watt hour 33 | $wattHour = UnitOfMeasure::linearUnitFactory('Wh', 3600); 34 | $wattHour->addAlias('watt hour'); 35 | $wattHour->addAlias('watt hours'); 36 | static::addUnit($wattHour); 37 | 38 | static::addMissingSIPrefixedUnits( 39 | $wattHour, 40 | 1, 41 | '%pWh', 42 | [ 43 | '%Pwatt hour', 44 | '%Pwatt hours', 45 | ] 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Length.php: -------------------------------------------------------------------------------- 1 | addAlias('meter'); 19 | $meter->addAlias('meters'); 20 | $meter->addAlias('metre'); 21 | $meter->addAlias('metres'); 22 | static::addUnit($meter); 23 | 24 | static::addMissingSIPrefixedUnits( 25 | $meter, 26 | 1, 27 | '%pm', 28 | [ 29 | '%Pmeter', 30 | '%Pmeters', 31 | '%Pmetre', 32 | '%Pmetres' 33 | ] 34 | ); 35 | 36 | // Foot 37 | $newUnit = UnitOfMeasure::linearUnitFactory('ft', 0.3048); 38 | $newUnit->addAlias('foot'); 39 | $newUnit->addAlias('feet'); 40 | static::addUnit($newUnit); 41 | 42 | // Inch 43 | $newUnit = UnitOfMeasure::linearUnitFactory('in', 0.0254); 44 | $newUnit->addAlias('inch'); 45 | $newUnit->addAlias('inches'); 46 | static::addUnit($newUnit); 47 | 48 | // Mile 49 | $newUnit = UnitOfMeasure::linearUnitFactory('mi', 1609.344); 50 | $newUnit->addAlias('mile'); 51 | $newUnit->addAlias('miles'); 52 | static::addUnit($newUnit); 53 | 54 | // Yard 55 | $newUnit = UnitOfMeasure::linearUnitFactory('yd', 0.9144); 56 | $newUnit->addAlias('yard'); 57 | $newUnit->addAlias('yards'); 58 | static::addUnit($newUnit); 59 | 60 | // Nautical mile 61 | $newUnit = UnitOfMeasure::linearUnitFactory('M', 1852); 62 | $newUnit->addAlias('nautical mile'); 63 | $newUnit->addAlias('nautical miles'); 64 | $newUnit->addAlias('nmi'); 65 | $newUnit->addAlias('NM'); 66 | static::addUnit($newUnit); 67 | 68 | // Scandinavian mil 69 | $newUnit = UnitOfMeasure::linearUnitFactory('mil', 10000); 70 | static::addUnit($newUnit); 71 | 72 | // Astronomical Unit 73 | $newUnit = UnitOfMeasure::linearUnitFactory('AU', 149597870700); 74 | $newUnit->addAlias('au'); 75 | $newUnit->addAlias('astronomical unit'); 76 | $newUnit->addAlias('astronomical units'); 77 | static::addUnit($newUnit); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/LuminousIntensity.php: -------------------------------------------------------------------------------- 1 | addAlias('candela'); 19 | static::addUnit($candela); 20 | 21 | static::addMissingSIPrefixedUnits( 22 | $candela, 23 | 1, 24 | '%pcd', 25 | [ 26 | '%Pcandela', 27 | ] 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Mass.php: -------------------------------------------------------------------------------- 1 | addAlias('kilogram'); 19 | $kilogram->addAlias('kilograms'); 20 | static::addUnit($kilogram); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $kilogram, 24 | 1e-3, 25 | '%pg', 26 | [ 27 | '%Pgram', 28 | '%Pgrams', 29 | ] 30 | ); 31 | 32 | // Tonne (metric) 33 | $newUnit = UnitOfMeasure::linearUnitFactory('t', 1e3); 34 | $newUnit->addAlias('ton'); 35 | $newUnit->addAlias('tons'); 36 | $newUnit->addAlias('tonne'); 37 | $newUnit->addAlias('tonnes'); 38 | static::addUnit($newUnit); 39 | 40 | // Pound 41 | $newUnit = UnitOfMeasure::linearUnitFactory('lb', 4.5359237e-1); 42 | $newUnit->addAlias('lbs'); 43 | $newUnit->addAlias('pound'); 44 | $newUnit->addAlias('pounds'); 45 | static::addUnit($newUnit); 46 | 47 | // Ounce 48 | $newUnit = UnitOfMeasure::linearUnitFactory('oz', 4.5359237e-1 / 16); 49 | $newUnit->addAlias('ounce'); 50 | $newUnit->addAlias('ounces'); 51 | static::addUnit($newUnit); 52 | 53 | // Stone 54 | $newUnit = UnitOfMeasure::linearUnitFactory('st', 4.5359237e-1 * 14); 55 | $newUnit->addAlias('stone'); 56 | $newUnit->addAlias('stones'); 57 | static::addUnit($newUnit); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Power.php: -------------------------------------------------------------------------------- 1 | addAlias('watt'); 19 | $watt->addAlias('watts'); 20 | static::addUnit($watt); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $watt, 24 | 1, 25 | '%pW', 26 | [ 27 | '%Pwatt', 28 | '%Pwatts', 29 | ] 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Pressure.php: -------------------------------------------------------------------------------- 1 | addAlias('pascal'); 19 | static::addUnit($pascal); 20 | 21 | static::addMissingSIPrefixedUnits( 22 | $pascal, 23 | 1, 24 | '%pPa', 25 | [ 26 | '%Ppascal', 27 | ] 28 | ); 29 | 30 | // Atmosphere 31 | $newUnit = UnitOfMeasure::linearUnitFactory('atm', 101325); 32 | $newUnit->addAlias('atmosphere'); 33 | $newUnit->addAlias('atmospheres'); 34 | static::addUnit($newUnit); 35 | 36 | // Bar 37 | $bar = UnitOfMeasure::linearUnitFactory('bar', 1e5); 38 | static::addUnit($bar); 39 | 40 | static::addMissingSIPrefixedUnits( 41 | $bar, 42 | 1, 43 | '%pbar' 44 | ); 45 | 46 | // Inch of Mercury 47 | $newUnit = UnitOfMeasure::linearUnitFactory('inHg', 3.386389e3); 48 | $newUnit->addAlias('inches of mercury'); 49 | static::addUnit($newUnit); 50 | 51 | // Millimeter of Mercury 52 | $newUnit = UnitOfMeasure::linearUnitFactory('mmHg', 133.3224); 53 | $newUnit->addAlias('millimeters of mercury'); 54 | $newUnit->addAlias('millimetres of mercury'); 55 | $newUnit->addAlias('torr'); 56 | static::addUnit($newUnit); 57 | 58 | // Pound per Square Inch 59 | $newUnit = UnitOfMeasure::linearUnitFactory('psi', 6.894757e3); 60 | $newUnit->addAlias('pounds per square inch'); 61 | static::addUnit($newUnit); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Quantity.php: -------------------------------------------------------------------------------- 1 | addAlias('mole'); 19 | $mole->addAlias('moles'); 20 | static::addUnit($mole); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $mole, 24 | 1, 25 | '%pmol', 26 | [ 27 | '%Pmole', 28 | '%Pmoles', 29 | ] 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/SolidAngle.php: -------------------------------------------------------------------------------- 1 | addAlias('steradian'); 19 | $steradian->addAlias('steradians'); 20 | static::addUnit($steradian); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $steradian, 24 | 1, 25 | '%psr', 26 | [ 27 | '%Psteradian', 28 | '%Psteradians', 29 | ] 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Temperature.php: -------------------------------------------------------------------------------- 1 | addAlias('°K'); 19 | $kelvin->addAlias('kelvin'); 20 | static::addUnit($kelvin); 21 | 22 | static::addMissingSIPrefixedUnits( 23 | $kelvin, 24 | 1, 25 | '%pK', 26 | [ 27 | '%Pkelvin', 28 | ] 29 | ); 30 | 31 | // Degree Celsius 32 | $newUnit = new UnitOfMeasure( 33 | '°C', 34 | function ($x) { 35 | return $x - 273.15; 36 | }, 37 | function ($x) { 38 | return $x + 273.15; 39 | } 40 | ); 41 | $newUnit->addAlias('C'); 42 | $newUnit->addAlias('celsius'); 43 | static::addUnit($newUnit); 44 | 45 | // Degree Fahrenheit 46 | $newUnit = new UnitOfMeasure( 47 | '°F', 48 | function ($x) { 49 | return ($x * 9 / 5) - 459.67; 50 | }, 51 | function ($x) { 52 | return ($x + 459.67) * 5/9; 53 | } 54 | ); 55 | $newUnit->addAlias('F'); 56 | $newUnit->addAlias('fahrenheit'); 57 | static::addUnit($newUnit); 58 | 59 | // Degree Rankine 60 | $newUnit = UnitOfMeasure::linearUnitFactory('°R', 5/9); 61 | $newUnit->addAlias('R'); 62 | $newUnit->addAlias('rankine'); 63 | static::addUnit($newUnit); 64 | 65 | // Degree Delisle 66 | $newUnit = new UnitOfMeasure( 67 | '°De', 68 | function ($x) { 69 | return (373.15 - $x) * 3/2; 70 | }, 71 | function ($x) { 72 | return 373.15 - $x * 2/3; 73 | } 74 | ); 75 | $newUnit->addAlias('De'); 76 | $newUnit->addAlias('delisle'); 77 | static::addUnit($newUnit); 78 | 79 | // Degree Newton 80 | $newUnit = new UnitOfMeasure( 81 | '°N', 82 | function ($x) { 83 | return ($x - 273.15) * 33/100; 84 | }, 85 | function ($x) { 86 | return $x * 100/33 + 273.15; 87 | } 88 | ); 89 | $newUnit->addAlias('N'); 90 | $newUnit->addAlias('newton'); 91 | static::addUnit($newUnit); 92 | 93 | // Degree Réaumur 94 | $newUnit = new UnitOfMeasure( 95 | '°Ré', 96 | function ($x) { 97 | return ($x - 273.15) * 4/5; 98 | }, 99 | function ($x) { 100 | return $x * 5/4 + 273.15; 101 | } 102 | ); 103 | $newUnit->addAlias('°Re'); 104 | $newUnit->addAlias('Ré'); 105 | $newUnit->addAlias('Re'); 106 | $newUnit->addAlias('réaumur'); 107 | $newUnit->addAlias('reaumur'); 108 | static::addUnit($newUnit); 109 | 110 | // Degree Rømer 111 | $newUnit = new UnitOfMeasure( 112 | '°Rø', 113 | function ($x) { 114 | return ($x - 273.15) * 21/40 + 7.5; 115 | }, 116 | function ($x) { 117 | return ($x - 7.5) * 40/21 + 273.15; 118 | } 119 | ); 120 | $newUnit->addAlias('°Ro'); 121 | $newUnit->addAlias('Rø'); 122 | $newUnit->addAlias('Ro'); 123 | $newUnit->addAlias('rømer'); 124 | $newUnit->addAlias('romer'); 125 | static::addUnit($newUnit); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Time.php: -------------------------------------------------------------------------------- 1 | addAlias('sec'); 19 | $second->addAlias('secs'); 20 | $second->addAlias('second'); 21 | $second->addAlias('seconds'); 22 | static::addUnit($second); 23 | 24 | static::addMissingSIPrefixedUnits( 25 | $second, 26 | 1, 27 | '%ps', 28 | [ 29 | '%Psec', 30 | '%Psecs', 31 | '%Psecond', 32 | '%Pseconds' 33 | ] 34 | ); 35 | 36 | // Minutes 37 | $newUnit = UnitOfMeasure::linearUnitFactory('m', 60); 38 | $newUnit->addAlias('min'); 39 | $newUnit->addAlias('mins'); 40 | $newUnit->addAlias('minute'); 41 | $newUnit->addAlias('minutes'); 42 | static::addUnit($newUnit); 43 | 44 | // Hours 45 | $newUnit = UnitOfMeasure::linearUnitFactory('h', 3600); 46 | $newUnit->addAlias('hr'); 47 | $newUnit->addAlias('hrs'); 48 | $newUnit->addAlias('hour'); 49 | $newUnit->addAlias('hours'); 50 | static::addUnit($newUnit); 51 | 52 | // Days 53 | $newUnit = UnitOfMeasure::linearUnitFactory('d', 86400); 54 | $newUnit->addAlias('day'); 55 | $newUnit->addAlias('days'); 56 | static::addUnit($newUnit); 57 | 58 | // Weeks, understood as 7 days 59 | $newUnit = UnitOfMeasure::linearUnitFactory('w', 604800); 60 | $newUnit->addAlias('wk'); 61 | $newUnit->addAlias('wks'); 62 | $newUnit->addAlias('week'); 63 | $newUnit->addAlias('weeks'); 64 | static::addUnit($newUnit); 65 | 66 | // Gregorian year, understood as 365.2425 days 67 | $newUnit = UnitOfMeasure::linearUnitFactory('yr', 31556952); 68 | $newUnit->addAlias('year'); 69 | $newUnit->addAlias('years'); 70 | $newUnit->addAlias('gregorian year'); 71 | $newUnit->addAlias('gregorian years'); 72 | static::addUnit($newUnit); 73 | 74 | // Decade 75 | $newUnit = UnitOfMeasure::linearUnitFactory('decade', 315569520); 76 | $newUnit->addAlias('decades'); 77 | static::addUnit($newUnit); 78 | 79 | // Century 80 | $newUnit = UnitOfMeasure::linearUnitFactory('century', 3155695200); 81 | $newUnit->addAlias('centuries'); 82 | static::addUnit($newUnit); 83 | 84 | // Millennium 85 | $newUnit = UnitOfMeasure::linearUnitFactory('millennium', 31556952000); 86 | $newUnit->addAlias('millennia'); 87 | static::addUnit($newUnit); 88 | 89 | // Julian year, understood as 365.25 days 90 | $newUnit = UnitOfMeasure::linearUnitFactory('jyr', 31557600); 91 | $newUnit->addAlias('julian year'); 92 | $newUnit->addAlias('julian years'); 93 | static::addUnit($newUnit); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Velocity.php: -------------------------------------------------------------------------------- 1 | addAlias('meters/sec'); 16 | $meterpersecond->addAlias('meters per second'); 17 | $meterpersecond->addAlias('meter per second'); 18 | $meterpersecond->addAlias('metres per second'); 19 | $meterpersecond->addAlias('metre per second'); 20 | static::addUnit($meterpersecond); 21 | 22 | // kilometers per hour 23 | $newUnit = UnitOfMeasure::linearUnitFactory('km/h', 0.277778); 24 | $newUnit->addAlias('km/hour'); 25 | $newUnit->addAlias('kilometer per hour'); 26 | $newUnit->addAlias('kilometers per hour'); 27 | $newUnit->addAlias('kilometre per hour'); 28 | $newUnit->addAlias('kilometres per hour'); 29 | static::addUnit($newUnit); 30 | 31 | // feet per second 32 | $newUnit = UnitOfMeasure::linearUnitFactory('ft/s', 0.3048); 33 | $newUnit->addAlias('feet/sec'); 34 | $newUnit->addAlias('feet per second'); 35 | static::addUnit($newUnit); 36 | 37 | // miles per hour 38 | $newUnit = UnitOfMeasure::linearUnitFactory('mph', 0.44704); 39 | $newUnit->addAlias('miles/hour'); 40 | $newUnit->addAlias('miles per hour'); 41 | static::addUnit($newUnit); 42 | 43 | // knot 44 | $newUnit = UnitOfMeasure::linearUnitFactory('knot', 0.514444); 45 | $newUnit->addAlias('knots'); 46 | static::addUnit($newUnit); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /source/PhysicalQuantity/Volume.php: -------------------------------------------------------------------------------- 1 | addAlias('m³'); 16 | $cubicmeter->addAlias('cubic meter'); 17 | $cubicmeter->addAlias('cubic meters'); 18 | $cubicmeter->addAlias('cubic metre'); 19 | $cubicmeter->addAlias('cubic metres'); 20 | static::addUnit($cubicmeter); 21 | 22 | // Cubic millimeter 23 | $newUnit = UnitOfMeasure::linearUnitFactory('mm^3', 1e-9); 24 | $newUnit->addAlias('mm³'); 25 | $newUnit->addAlias('cubic millimeter'); 26 | $newUnit->addAlias('cubic millimeters'); 27 | $newUnit->addAlias('cubic millimetre'); 28 | $newUnit->addAlias('cubic millimetres'); 29 | static::addUnit($newUnit); 30 | 31 | // Cubic centimeter 32 | $newUnit = UnitOfMeasure::linearUnitFactory('cm^3', 1e-6); 33 | $newUnit->addAlias('cm³'); 34 | $newUnit->addAlias('cubic centimeter'); 35 | $newUnit->addAlias('cubic centimeters'); 36 | $newUnit->addAlias('cubic centimetre'); 37 | $newUnit->addAlias('cubic centimetres'); 38 | static::addUnit($newUnit); 39 | 40 | // Cubic decimeter 41 | $newUnit = UnitOfMeasure::linearUnitFactory('dm^3', 1e-3); 42 | $newUnit->addAlias('dm³'); 43 | $newUnit->addAlias('cubic decimeter'); 44 | $newUnit->addAlias('cubic decimeters'); 45 | $newUnit->addAlias('cubic decimetre'); 46 | $newUnit->addAlias('cubic decimetres'); 47 | static::addUnit($newUnit); 48 | 49 | // Cubic kilometer 50 | $newUnit = UnitOfMeasure::linearUnitFactory('km^3', 1e9); 51 | $newUnit->addAlias('km³'); 52 | $newUnit->addAlias('cubic kilometer'); 53 | $newUnit->addAlias('cubic kilometers'); 54 | $newUnit->addAlias('cubic kilometre'); 55 | $newUnit->addAlias('cubic kilometres'); 56 | static::addUnit($newUnit); 57 | 58 | // Cubic foot 59 | $newUnit = UnitOfMeasure::linearUnitFactory('ft^3', 2.831685e-2); 60 | $newUnit->addAlias('ft³'); 61 | $newUnit->addAlias('cubic foot'); 62 | $newUnit->addAlias('cubic feet'); 63 | static::addUnit($newUnit); 64 | 65 | // Cubic inch 66 | $newUnit = UnitOfMeasure::linearUnitFactory('in^3', 1.638706e-5); 67 | $newUnit->addAlias('in³'); 68 | $newUnit->addAlias('cubic inch'); 69 | $newUnit->addAlias('cubic inches'); 70 | static::addUnit($newUnit); 71 | 72 | // Cubic yard 73 | $newUnit = UnitOfMeasure::linearUnitFactory('yd^3', 7.645549e-1); 74 | $newUnit->addAlias('yd³'); 75 | $newUnit->addAlias('cubic yard'); 76 | $newUnit->addAlias('cubic yards'); 77 | static::addUnit($newUnit); 78 | 79 | // Milliliters 80 | $newUnit = UnitOfMeasure::linearUnitFactory('ml', 1e-6); 81 | $newUnit->addAlias('milliliter'); 82 | $newUnit->addAlias('milliliters'); 83 | $newUnit->addAlias('millilitre'); 84 | $newUnit->addAlias('millilitres'); 85 | static::addUnit($newUnit); 86 | 87 | // Centiliters 88 | $newUnit = UnitOfMeasure::linearUnitFactory('cl', 1e-5); 89 | $newUnit->addAlias('centiliter'); 90 | $newUnit->addAlias('centiliters'); 91 | $newUnit->addAlias('centilitre'); 92 | $newUnit->addAlias('centilitres'); 93 | static::addUnit($newUnit); 94 | 95 | // Deciliter 96 | $newUnit = UnitOfMeasure::linearUnitFactory('dl', 1e-4); 97 | $newUnit->addAlias('deciliter'); 98 | $newUnit->addAlias('deciliters'); 99 | $newUnit->addAlias('decilitre'); 100 | $newUnit->addAlias('decilitres'); 101 | static::addUnit($newUnit); 102 | 103 | // Liter 104 | $newUnit = UnitOfMeasure::linearUnitFactory('l', 1e-3); 105 | $newUnit->addAlias('liter'); 106 | $newUnit->addAlias('liters'); 107 | $newUnit->addAlias('litre'); 108 | $newUnit->addAlias('litres'); 109 | static::addUnit($newUnit); 110 | 111 | // Decaliter 112 | $newUnit = UnitOfMeasure::linearUnitFactory('dal', 1e-2); 113 | $newUnit->addAlias('decaliter'); 114 | $newUnit->addAlias('decaliters'); 115 | $newUnit->addAlias('decalitre'); 116 | $newUnit->addAlias('decalitres'); 117 | static::addUnit($newUnit); 118 | 119 | // Hectoliter 120 | $newUnit = UnitOfMeasure::linearUnitFactory('hl', 1e-1); 121 | $newUnit->addAlias('hectoliter'); 122 | $newUnit->addAlias('hectoliters'); 123 | $newUnit->addAlias('hectolitre'); 124 | $newUnit->addAlias('hectolitres'); 125 | static::addUnit($newUnit); 126 | 127 | // Cup 128 | $newUnit = UnitOfMeasure::linearUnitFactory('cup', 2.365882e-4); 129 | $newUnit->addAlias('cup'); 130 | $newUnit->addAlias('cups'); 131 | static::addUnit($newUnit); 132 | 133 | // teaspoon 134 | $newUnit = UnitOfMeasure::linearUnitFactory('tsp', 0.00000492892); 135 | $newUnit->addAlias('teaspoon'); 136 | $newUnit->addAlias('teaspoons'); 137 | static::addUnit($newUnit); 138 | 139 | // tablespoon 140 | $newUnit = UnitOfMeasure::linearUnitFactory('tbsp', 0.00001478676); 141 | $newUnit->addAlias('tablespoon'); 142 | $newUnit->addAlias('tablespoons'); 143 | static::addUnit($newUnit); 144 | 145 | // Gallon 146 | $newUnit = UnitOfMeasure::linearUnitFactory('gal', 3.7854118e-3); 147 | $newUnit->addAlias('gallon'); 148 | $newUnit->addAlias('gallons'); 149 | $newUnit->addAlias('us gal'); 150 | static::addUnit($newUnit); 151 | 152 | // Imperial Gallon 153 | $newUnit = UnitOfMeasure::linearUnitFactory('imp gal', 4.54609e-3); 154 | $newUnit->addAlias('imperial gallon'); 155 | $newUnit->addAlias('imperial gal'); 156 | $newUnit->addAlias('imp gallon'); 157 | $newUnit->addAlias('impg'); 158 | static::addUnit($newUnit); 159 | 160 | // Quart 161 | $newUnit = UnitOfMeasure::linearUnitFactory('qt', 9.4635295e-4); 162 | $newUnit->addAlias('quart'); 163 | $newUnit->addAlias('quarts'); 164 | $newUnit->addAlias('qts'); 165 | $newUnit->addAlias('liq qt'); 166 | static::addUnit($newUnit); 167 | // Fluid Ounce 168 | $newUnit = UnitOfMeasure::linearUnitFactory('fl oz', 2.957353e-5); 169 | $newUnit->addAlias('fluid ounce'); 170 | $newUnit->addAlias('fluid ounces'); 171 | $newUnit->addAlias('fluid oz'); 172 | $newUnit->addAlias('fl. oz.'); 173 | $newUnit->addAlias('oz. fl.'); 174 | static::addUnit($newUnit); 175 | // Pint 176 | $newUnit = UnitOfMeasure::linearUnitFactory('pt', 4.73176475e-4); 177 | $newUnit->addAlias('pint'); 178 | $newUnit->addAlias('pints'); 179 | $newUnit->addAlias('liq pt'); 180 | static::addUnit($newUnit); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /source/PhysicalQuantityInterface.php: -------------------------------------------------------------------------------- 1 | $name]); 99 | } 100 | 101 | $this->name = $name; 102 | $this->fromNativeUnit = $fromNativeUnit; 103 | $this->toNativeUnit = $toNativeUnit; 104 | } 105 | 106 | /** 107 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::getName 108 | */ 109 | public function getName() 110 | { 111 | return $this->name; 112 | } 113 | 114 | /** 115 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::addAlias 116 | */ 117 | public function addAlias($alias) 118 | { 119 | if (!is_string($alias)) { 120 | throw new Exception\NonStringUnitName([':name' => $alias]); 121 | } 122 | 123 | $this->aliases[] = $alias; 124 | } 125 | 126 | /** 127 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::getAliases 128 | */ 129 | public function getAliases() 130 | { 131 | return $this->aliases; 132 | } 133 | 134 | /** 135 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::isAliasOf 136 | */ 137 | public function isAliasOf($unit) 138 | { 139 | if (!is_string($unit)) { 140 | throw new Exception\NonStringUnitName([':name' => $unit]); 141 | } 142 | 143 | return in_array($unit, $this->aliases); 144 | } 145 | 146 | /** 147 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::convertValueFromNativeUnitOfMeasure 148 | */ 149 | public function convertValueFromNativeUnitOfMeasure($value) 150 | { 151 | if (!is_numeric($value)) { 152 | throw new Exception\NonNumericValue([':value' => $value]); 153 | } 154 | 155 | $callable = $this->fromNativeUnit; 156 | return $callable($value); 157 | } 158 | 159 | /** 160 | * @see \PhpUnitsOfMeasure\UnitOfMeasureInterface::convertValueToNativeUnitOfMeasure 161 | */ 162 | public function convertValueToNativeUnitOfMeasure($value) 163 | { 164 | if (!is_numeric($value)) { 165 | throw new Exception\NonNumericValue([':value' => $value]); 166 | } 167 | 168 | $callable = $this->toNativeUnit; 169 | return $callable($value); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /source/UnitOfMeasureInterface.php: -------------------------------------------------------------------------------- 1 | getMockBuilder(UnitOfMeasureInterface::class) 24 | ->getMock(); 25 | $newUnit->method('getName') 26 | ->willReturn($name); 27 | $newUnit->method('getAliases') 28 | ->willReturn($aliases); 29 | $newUnit->method('isAliasOf') 30 | ->will($this->returnCallback( 31 | function ($value) use ($aliases) { 32 | return in_array($value, $aliases); 33 | } 34 | )); 35 | 36 | return $newUnit; 37 | } 38 | 39 | /** 40 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::addUnit 41 | */ 42 | public function testAddUnit(): void 43 | { 44 | $newUnit = $this->getTestUnitOfMeasure('noconflict', ['definitelynoconflict']); 45 | 46 | Wonkicity::addUnit($newUnit); 47 | } 48 | 49 | /** 50 | * @dataProvider exceptionProducingUnitsProvider 51 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::addUnit 52 | */ 53 | public function testAddUnitFailsOnNameCollision($unitName, $unitAliases): void 54 | { 55 | $this->expectException(\PhpUnitsOfMeasure\Exception\DuplicateUnitNameOrAlias::class); 56 | $newUnit = $this->getTestUnitOfMeasure($unitName, $unitAliases); 57 | 58 | Wonkicity::addUnit($newUnit); 59 | } 60 | 61 | /** 62 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::getUnit 63 | */ 64 | public function testGetUnit(): void 65 | { 66 | $unit = Wonkicity::getUnit('u'); 67 | 68 | $this->assertSame('u', $unit->getName()); 69 | } 70 | 71 | /** 72 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::getUnit 73 | */ 74 | public function testGetUnitFailsOnUnknownUnit(): void 75 | { 76 | $this->expectException(\PhpUnitsOfMeasure\Exception\UnknownUnitOfMeasure::class); 77 | Wonkicity::getUnit('someUnknownUnit'); 78 | } 79 | 80 | /** 81 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::__construct 82 | */ 83 | public function testInstantiateNewUnit(): void 84 | { 85 | $value = new Wonkicity(1.234, 'quatloos'); 86 | } 87 | 88 | /** 89 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::__construct 90 | */ 91 | public function testInstantiateNewUnitNonNumericValue(): void 92 | { 93 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonNumericValue::class); 94 | $value = new Wonkicity('string', 'quatloos'); 95 | } 96 | 97 | /** 98 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::__construct 99 | */ 100 | public function testInstantiateNewUnitNonStringUnit(): void 101 | { 102 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonStringUnitName::class); 103 | $value = new Wonkicity(1.234, 42); 104 | } 105 | 106 | /** 107 | * @dataProvider quantityConversionsProvider 108 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::toUnit 109 | */ 110 | public function testConvertToUnknownUnitThrowsException( 111 | AbstractPhysicalQuantity $value, 112 | $arbitraryUnit, 113 | $valueInArbitraryUnit 114 | ): void { 115 | $this->expectException(\PhpUnitsOfMeasure\Exception\UnknownUnitOfMeasure::class); 116 | $value->toUnit('someUnknownUnit'); 117 | } 118 | 119 | /** 120 | * @dataProvider quantityConversionsProvider 121 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::toNativeUnit 122 | */ 123 | public function testUnitConvertsToArbitraryUnit( 124 | AbstractPhysicalQuantity $value, 125 | $arbitraryUnit, 126 | $valueInArbitraryUnit 127 | ): void { 128 | $this->assertSame($valueInArbitraryUnit, $value->toUnit($arbitraryUnit)); 129 | } 130 | 131 | /** 132 | * @dataProvider toStringProvider 133 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::__toString 134 | */ 135 | public function testToString(AbstractPhysicalQuantity $value, $string): void 136 | { 137 | $this->assertSame($string, (string) $value); 138 | } 139 | 140 | /** 141 | * @dataProvider quantityConversionsProvider 142 | */ 143 | public function testSerialize( 144 | AbstractPhysicalQuantity $value, 145 | $arbitraryUnit, 146 | $valueInArbitraryUnit 147 | ): void { 148 | serialize($value); 149 | } 150 | 151 | /** 152 | * @dataProvider quantityConversionsProvider 153 | */ 154 | public function testUnserialize( 155 | AbstractPhysicalQuantity $value, 156 | $arbitraryUnit, 157 | $valueInArbitraryUnit 158 | ): void { 159 | $unserializedValue = unserialize(serialize($value)); 160 | 161 | $this->assertSame($valueInArbitraryUnit, $unserializedValue->toUnit($arbitraryUnit)); 162 | } 163 | 164 | /** 165 | * @dataProvider arithmeticProvider 166 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::add 167 | */ 168 | public function testAdd( 169 | $shouldThrowException, 170 | AbstractPhysicalQuantity $firstValue, 171 | AbstractPhysicalQuantity $secondValue, 172 | $sumString, 173 | $diffString 174 | ): void { 175 | if ($shouldThrowException) { 176 | $this->expectException(PhysicalQuantityMismatch::class); 177 | } 178 | 179 | $sum = $firstValue->add($secondValue); 180 | 181 | if (!$shouldThrowException) { 182 | $this->assertSame($sumString, (string) $sum); 183 | } 184 | } 185 | 186 | /** 187 | * @dataProvider arithmeticProvider 188 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::subtract 189 | */ 190 | public function testSubtract( 191 | $shouldThrowException, 192 | AbstractPhysicalQuantity $firstValue, 193 | AbstractPhysicalQuantity $secondValue, 194 | $sumString, 195 | $diffString 196 | ): void { 197 | if ($shouldThrowException) { 198 | $this->expectException(PhysicalQuantityMismatch::class); 199 | } 200 | 201 | $difference = $firstValue->subtract($secondValue); 202 | 203 | if (!$shouldThrowException) { 204 | $this->assertSame($diffString, (string) $difference); 205 | } 206 | } 207 | 208 | /** 209 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::getUnitDefinitions 210 | */ 211 | public function testGetAllUnits(): void 212 | { 213 | $array = Wonkicity::getUnitDefinitions(); 214 | 215 | $this->assertIsArray($array); 216 | 217 | $expected = array(Wonkicity::getUnit('u'), Wonkicity::getUnit('v')); 218 | $this->assertEquals($array, $expected); 219 | } 220 | 221 | /** 222 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::isUnitDefined 223 | */ 224 | public function testIsUnitDefined(): void 225 | { 226 | $newUnit = $this->getTestUnitOfMeasure('noconflict', ['definitelynoconflict_1', 'definitelynoconflict_2']); 227 | Wonkicity::addUnit($newUnit); 228 | 229 | $someExistingUnits = ['u', 'uvees', 'v', 'vorp', 'noconflict', 'definitelynoconflict_1', 'definitelynoconflict_2']; 230 | $unexistingUnits = ['kg', 'l', 'definitelynoconflict_']; 231 | 232 | foreach ($someExistingUnits as $someExistingUnit) { 233 | $this->assertTrue(Wonkicity::isUnitDefined($someExistingUnit), "$someExistingUnit is not defined"); 234 | } 235 | foreach ($unexistingUnits as $unexistingUnit) { 236 | $this->assertFalse(Wonkicity::isUnitDefined($unexistingUnit), "$unexistingUnit is not defined"); 237 | } 238 | } 239 | 240 | /** 241 | * @covers \PhpUnitsOfMeasure\AbstractPhysicalQuantity::listAllUnits 242 | */ 243 | public function testListAllUnits(): void 244 | { 245 | $newUnit = $this->getTestUnitOfMeasure('noconflict', ['definitelynoconflict_1', 'definitelynoconflict_2']); 246 | Wonkicity::addUnit($newUnit); 247 | 248 | $allUnits = Wonkicity::listAllUnits(); 249 | $expected = []; 250 | $expected['u'] = ['uvee', 'uvees']; 251 | $expected['v'] = ['vorp', 'vorps']; 252 | $expected['noconflict'] = ['definitelynoconflict_1', 'definitelynoconflict_2']; 253 | $this->assertEquals($allUnits, $expected); 254 | } 255 | 256 | public function testGetOriginalValue() 257 | { 258 | $value = 2; 259 | $unit = 'u'; 260 | $physicalQuantity = new Wonkicity($value, $unit); 261 | $this->assertEquals($value, $physicalQuantity->getOriginalValue()); 262 | $this->assertEquals($unit, $physicalQuantity->getOriginalUnit()); 263 | } 264 | 265 | /** 266 | * Attempting to register these units should throw a DuplicateUnitNameOrAlias. 267 | * 1) The name of the new unit to test 268 | * 2) The set of aliases for the new unit to test 269 | */ 270 | public function exceptionProducingUnitsProvider(): array 271 | { 272 | return [ 273 | ['u', []], // new name / existing name collision 274 | ['noconflict', ['u']], // new alias / existing name collision 275 | ['uvee', []], // new name / existing alias collision 276 | ['noconflict', ['uvee']], // new alias / existing alias collision 277 | ]; 278 | } 279 | 280 | /** 281 | * Provide some conversion testing data 282 | * 1) the object from which to start 283 | * 2) The unit name to which to convert 284 | * 3) The expected resulting value of the conversion 285 | */ 286 | public function quantityConversionsProvider(): array 287 | { 288 | return [ 289 | [new Wonkicity(2, 'u'), 'u', 2], 290 | [new Wonkicity(2, 'u'), 'vorps', 2/3.5], 291 | [new Wonkicity(2, 'vorps'), 'u', 2*3.5], 292 | [new Wonkicity(2, 'vorps'), 'vorps', 2.0], 293 | [new Woogosity(2, 'p'), 'lupees', 2*4.5], 294 | [new Woogosity(2, 'p'), 'millilupees', 2*4.5*1000], 295 | ]; 296 | } 297 | 298 | /** 299 | * Provide some string conversion testing data 300 | * 1) The object which will be cast to a string 301 | * 2) the expected resulting string from the conversion 302 | */ 303 | public function toStringProvider(): array 304 | { 305 | return [ 306 | [new Wonkicity(2, 'u'), '2 u'], 307 | [new Wonkicity(2, 'uvee'), '2 u'], 308 | [new Wonkicity(2, 'v'), '2 v'], 309 | [new Wonkicity(2, 'vorps'), '2 v'], 310 | [new Woogosity(2, 'plurps'), '2 p'], 311 | [new Woogosity(2, 'millilupees'), '2 ml'], 312 | ]; 313 | } 314 | 315 | /** 316 | * Provide some arithmetic relations for testing 317 | * 1) Boolean - whether or not the operation shoul error out due to a type mismatch (PhysicalQuantityMismatch exception) 318 | * 2) The left-hand-side operand 319 | * 3) The right-hand-side operand 320 | * 4) The string-cast result of a sum operation with the two operands (ignored for errors) 321 | * 5) The string-cast result of a subtraction operation with the two operands (ignored for errors) 322 | */ 323 | public function arithmeticProvider(): array 324 | { 325 | return [ 326 | [false, new Wonkicity(2, 'u'), new Wonkicity(2.5, 'u'), '4.5 u', '-0.5 u'], 327 | [true, new Wonkicity(2, 'u'), new Woogosity(2, 'l'), '', ''], 328 | ]; 329 | } 330 | } 331 | -------------------------------------------------------------------------------- /tests/DemonstrationTests.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Wigginess::class, $a); 42 | 43 | $a = new Wigginess(2.123, 'sopees'); 44 | $this->assertInstanceOf(Wigginess::class, $a); 45 | 46 | $a = new Wigginess(2.6, 's'); 47 | $this->assertInstanceOf(Wigginess::class, $a); 48 | 49 | $a = new Wigginess(1, 'tumpet'); 50 | $this->assertInstanceOf(Wigginess::class, $a); 51 | 52 | $a = new Wigginess(2.123, 'tumpets'); 53 | $this->assertInstanceOf(Wigginess::class, $a); 54 | 55 | $a = new Wigginess(2.6, 't'); 56 | $this->assertInstanceOf(Wigginess::class, $a); 57 | } 58 | 59 | public function testStringConversionForQuantities(): void 60 | { 61 | // Casting physical quantity objects to strings will 62 | // produce a reasonable string describing the quantity. 63 | $a = new Wigginess(21.123, 'sopees'); 64 | $this->assertSame('21.123 s', (string) $a); 65 | 66 | $a = new Wigginess(21.123, 'tumpets'); 67 | $this->assertSame('21.123 t', (string) $a); 68 | } 69 | 70 | public function testUnitConversionForQuantities(): void 71 | { 72 | // Creating equivalent quantities from existing 73 | // quantities in different units of measure is done 74 | // with the toUnit() method. Note that the method 75 | // returns a new object, and does not modify the 76 | // unit of the object on which it is called. 77 | // 78 | // (In imaginary Testworld, 2.5 sopees is 1 tumpet. 79 | // See the Wigginess.php example class for details 80 | // on how these units are defined.) 81 | $a = new Wigginess(21, 'sopees'); 82 | $this->assertSame(21, $a->toUnit('sopee')); 83 | $this->assertSame(21/2.5, $a->toUnit('tumpets')); 84 | $this->assertSame(21/2.5, $a->toUnit('t')); 85 | } 86 | 87 | public function testCreatingNewUnitsForQuantities(): void 88 | { 89 | // New units of measure can be defined and registered 90 | // with physical quantities on the fly. 91 | 92 | // Here, we create three new units, demonstrating the 3 93 | // different methods for instantiating them. These units 94 | // will exist in addition to the units that come 'out of 95 | // the box' for the given quantity, once they're registered 96 | // with the static addUnit(). 97 | 98 | // The linear unit factory is useful for defining new 99 | // units that are a simple scaling factor conversion 100 | // to the quantity's native unit of measure. 101 | // In this case there are 4.5 bbbb's in the native unit of measure. 102 | $unitA = UnitOfMeasure::linearUnitFactory('bbbb', 4.5); 103 | Wigginess::addUnit($unitA); 104 | 105 | // Using the native unit factory method is equivalent to a 106 | // linear unit with a factor of 1. It's convenient for creating 107 | // a unit to represent the native unit of measure. 108 | $unitB = UnitOfMeasure::nativeUnitFactory('aaaa'); 109 | Wigginess::addUnit($unitB); 110 | 111 | // The long form constructor is necessary for units 112 | // that don't have simple scaling factor functions for 113 | // their conversions. For this unit we'll also add 2 more 114 | // aliases (dddd and eeee) that serve as equivalent names 115 | // for the unit's real name (cccc). 116 | $unitC = new UnitOfMeasure( 117 | 'cccc', 118 | function ($valueInNativeUnit) { 119 | return $valueInNativeUnit - 100; 120 | }, 121 | function ($valueInThisUnit) { 122 | return $valueInThisUnit + 100; 123 | } 124 | ); 125 | $unitC->addAlias('dddd'); 126 | $unitC->addAlias('eeee'); 127 | Wigginess::addUnit($unitC); 128 | 129 | 130 | // Here we can see that the units defined above 131 | // convert as expected with the built-in units. 132 | $a = new Wigginess(21, 'sopees'); 133 | $this->assertSame(21, $a->toUnit('aaaa')); 134 | $this->assertSame(21/4.5, $a->toUnit('bbbb')); 135 | $this->assertSame(21-100, $a->toUnit('cccc')); 136 | $this->assertSame(21-100, $a->toUnit('dddd')); 137 | $this->assertSame(21-100, $a->toUnit('eeee')); 138 | 139 | $b = new Wigginess(21, 'tumpets'); 140 | $this->assertSame(21*2.5, $b->toUnit('aaaa')); 141 | $this->assertSame(21/4.5*2.5, $b->toUnit('bbbb')); 142 | $this->assertSame((21*2.5)-100, $b->toUnit('cccc')); 143 | $this->assertSame((21*2.5)-100, $b->toUnit('dddd')); 144 | $this->assertSame((21*2.5)-100, $b->toUnit('eeee')); 145 | } 146 | 147 | public function testAutomaticSIUnitsForQuantities(): void 148 | { 149 | // SI units have a standard prefix naming convention to easily 150 | // provide powers-of-ten versions of a standard unit. For instance, 151 | // for the physical quantity length, the meter is the standard SI 152 | // unit, and 1000 meters is a kilometer, 1/1000th of a meter is a 153 | // millimeter, and so on. 154 | // 155 | // The Woogosity class has the HasSIUnitsTrait trait, and can 156 | // automatically generate new units for a given unit, for all 157 | // the standard SI prefixes. See the Woogosity.php class file 158 | // for an example of how this is done. 159 | $a = new Woogosity(21, 'plurp'); 160 | 161 | $this->assertInstanceOf(Woogosity::class, $a); 162 | $this->assertSame(21*4.5 * 1e3, $a->toUnit('millilupees')); 163 | $this->assertSame(21*4.5 * 1e3, $a->toUnit('ml')); 164 | $this->assertSame(21*4.5 / 1e6, $a->toUnit('megalupees')); 165 | $this->assertSame(21*4.5 / 1e6, $a->toUnit('Ml')); 166 | } 167 | 168 | public function testAddQuantities(): void 169 | { 170 | // Two quantities of equivalent value can be summed 171 | // by calling the add method. 172 | $a = new Wigginess(3, 'sopee'); 173 | $b = new Wigginess(2, 'tumpet'); 174 | $c = $a->add($b); 175 | 176 | $this->assertInstanceOf(Wigginess::class, $c); 177 | $this->assertSame(3 + (2*2.5), $c->toUnit('sopee')); 178 | } 179 | 180 | public function testSubtractQuantities(): void 181 | { 182 | // Similar to the add method, subtract called on the 183 | // left-hand-side operand object will subtract the 184 | // parameter quantity and produce a new value. 185 | $a = new Wigginess(3, 'sopee'); 186 | $b = new Wigginess(2, 'tumpet'); 187 | $c = $a->subtract($b); 188 | 189 | $this->assertInstanceOf(Wigginess::class, $c); 190 | $this->assertSame(3 - (2*2.5), $c->toUnit('sopee')); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /tests/Fixtures/PhysicalQuantity/Wigginess.php: -------------------------------------------------------------------------------- 1 | addAlias('sopee'); 16 | $native->addAlias('sopees'); 17 | static::addUnit($native); 18 | 19 | $unit = UnitOfMeasure::linearUnitFactory('t', 2.5); 20 | $unit->addAlias('tumpet'); 21 | $unit->addAlias('tumpets'); 22 | static::addUnit($unit); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Fixtures/PhysicalQuantity/Wonkicity.php: -------------------------------------------------------------------------------- 1 | addAlias('uvee'); 16 | $native->addAlias('uvees'); 17 | static::addUnit($native); 18 | 19 | $unit = UnitOfMeasure::linearUnitFactory('v', 3.5); 20 | $unit->addAlias('vorp'); 21 | $unit->addAlias('vorps'); 22 | static::addUnit($unit); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Fixtures/PhysicalQuantity/Woogosity.php: -------------------------------------------------------------------------------- 1 | addAlias('lupee'); 19 | $native->addAlias('lupees'); 20 | static::addUnit($native); 21 | static::addMissingSIPrefixedUnits( 22 | $native, 23 | 1, 24 | '%pl', 25 | [ 26 | '%Plupee', 27 | '%Plupees', 28 | ] 29 | ); 30 | 31 | $unit = UnitOfMeasure::linearUnitFactory('p', 4.5); 32 | $unit->addAlias('plurp'); 33 | $unit->addAlias('plurps'); 34 | static::addUnit($unit); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/AbstractPhysicalQuantityTestCase.php: -------------------------------------------------------------------------------- 1 | instantiateTestQuantity(); 21 | } 22 | 23 | /** 24 | * Convert to each of the known supported units, verifying that no 25 | * exceptions are thrown. 26 | */ 27 | public function testSupportedUnits(): void 28 | { 29 | $quantity = $this->instantiateTestQuantity(); 30 | 31 | foreach ($this->supportedUnitsWithAliases as $unit) { 32 | $quantity->toUnit($unit); 33 | } 34 | } 35 | 36 | /** 37 | * Build a test object of the target physical quantity. 38 | */ 39 | abstract protected function instantiateTestQuantity(): PhysicalQuantityInterface; 40 | } 41 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/AccelerationTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(360, $angle->toUnit('deg')); 262 | } 263 | 264 | public function testToRadians(): void 265 | { 266 | $angle = new Angle(720, 'degree'); 267 | $this->assertEquals(M_PI * 4, $angle->toUnit('rad')); 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/AreaTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(30000, $area->toUnit("m^2")); 75 | } 76 | 77 | /** 78 | * There aren't lots of super nice conversions between ac -> m^2, 79 | * so we'll check that it's close. 80 | */ 81 | public function testToAcres(): void 82 | { 83 | $area = new Area(13, 'ac'); 84 | 85 | $area = round($area->toUnit("m^2"), 6); 86 | 87 | $this->assertEquals(52609.133491, $area); 88 | } 89 | 90 | public function testToAre(): void 91 | { 92 | $area = new Area(100, 'm^2'); 93 | $this->assertEquals(1, $area->toUnit('are')); 94 | } 95 | 96 | public function testToDecare(): void 97 | { 98 | $area = new Area(1000, 'm^2'); 99 | $this->assertEquals(1, $area->toUnit('decare')); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/ElectricCurrentTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(1, $quantity->toUnit('kWh')); 71 | } 72 | 73 | public function testToWattHour(): void 74 | { 75 | $quantity = new Energy(1, 'kWh'); 76 | $this->assertEquals(1000, $quantity->toUnit('Wh')); 77 | } 78 | 79 | public function testToMegaJoule(): void 80 | { 81 | $quantity = new Energy(1, 'kWh'); 82 | $this->assertEquals(3.6, $quantity->toUnit('megajoule')); 83 | } 84 | 85 | public function testToJoule(): void 86 | { 87 | $quantity = new Energy(1, 'Wh'); 88 | $this->assertEquals(3600, $quantity->toUnit('joule')); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/LengthTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(5000, $quantity->toUnit('mm')); 148 | } 149 | 150 | public function testToMegameters(): void 151 | { 152 | $quantity = new Length(5, 'm'); 153 | $this->assertEquals(5/1e6, $quantity->toUnit('Mm')); 154 | } 155 | 156 | public function testToInches(): void 157 | { 158 | $quantity = new Length(2, 'ft'); 159 | $this->assertEquals(24, round($quantity->toUnit('in'))); 160 | } 161 | 162 | public function testToNauticalMiles(): void 163 | { 164 | $quantity = new Length(3704, 'm'); 165 | $this->assertEquals(2, $quantity->toUnit('nmi')); 166 | } 167 | 168 | public function testToScandinavianMil(): void 169 | { 170 | $quantity = new Length(20000, 'm'); 171 | $this->assertEquals(2, $quantity->toUnit('mil')); 172 | } 173 | 174 | public function testToAstronomicalUnit(): void 175 | { 176 | $quantity = new Length(150000000, 'km'); 177 | $this->assertEquals(1.0026880683402668, $quantity->toUnit('AU')); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/LuminousIntensityTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(5000, $quantity->toUnit('g')); 100 | } 101 | 102 | public function testToMilligrams(): void 103 | { 104 | $quantity = new Mass(5, 'kg'); 105 | $this->assertEquals(5*1e6, $quantity->toUnit('mg')); 106 | } 107 | 108 | public function testToPounds(): void 109 | { 110 | $quantity = new Mass(16, 'oz'); 111 | $this->assertEquals(1, $quantity->toUnit('pound')); 112 | } 113 | 114 | public function testToStones(): void 115 | { 116 | $quantity = new Mass(14, 'pound'); 117 | $this->assertEquals(1, $quantity->toUnit('st')); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/PowerTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(1, $quantity->toUnit('kW')); 46 | } 47 | 48 | public function testToWatt(): void 49 | { 50 | $quantity = new Power(1, 'kW'); 51 | $this->assertEquals(1000, $quantity->toUnit('W')); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/PressureTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(300, $angle->toUnit('seconds')); 153 | } 154 | 155 | public function testToMinutes(): void 156 | { 157 | $angle = new Time(360, 'sec'); 158 | $this->assertEquals(6, $angle->toUnit('min')); 159 | } 160 | 161 | public function testToHours(): void 162 | { 163 | $angle = new Time(120, 'mins'); 164 | $this->assertEquals(2, $angle->toUnit('hrs')); 165 | } 166 | 167 | public function testToDays(): void 168 | { 169 | $angle = new Time(72, 'hours'); 170 | $this->assertEquals(3, $angle->toUnit('days')); 171 | } 172 | 173 | public function testToWeeks(): void 174 | { 175 | $angle = new Time(14, 'd'); 176 | $this->assertEquals(2, $angle->toUnit('week')); 177 | } 178 | 179 | public function testToGregorianYears(): void 180 | { 181 | $angle = new Time(365.2425, 'd'); 182 | $this->assertEquals(1, $angle->toUnit('yr')); 183 | } 184 | 185 | public function testToJulianYears(): void 186 | { 187 | $angle = new Time(365.25, 'd'); 188 | $this->assertEquals(1, $angle->toUnit('jyr')); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/VelocityTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(0.277778, $speed->toUnit('m/s')); 42 | } 43 | 44 | public function testToFeetPerSecond(): void 45 | { 46 | $speed = new Velocity(2, 'm/s'); 47 | $this->assertEquals(6.561679790026246, $speed->toUnit('ft/s')); 48 | } 49 | 50 | public function testToKmPerHour(): void 51 | { 52 | $speed = new Velocity(2, 'mph'); 53 | $this->assertEquals(3.2186854250516594, $speed->toUnit('km/h')); 54 | } 55 | 56 | public function testToKnot(): void 57 | { 58 | $speed = new Velocity(2, 'm/s'); 59 | $this->assertEquals(3.8876923435786983, $speed->toUnit('knot')); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/PhysicalQuantity/VolumeTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('quatloos', $uom->getName()); 27 | } 28 | 29 | /** 30 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::__construct 31 | */ 32 | public function testConstructWithNonStringName(): void 33 | { 34 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonStringUnitName::class); 35 | $uom = new UnitOfMeasure( 36 | 42, 37 | function ($valueInNativeUnit) { 38 | return $valueInNativeUnit; 39 | }, 40 | function ($valueInThisUnit) { 41 | return $valueInThisUnit; 42 | } 43 | ); 44 | } 45 | 46 | /** 47 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::addAlias 48 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::getAliases 49 | */ 50 | public function testGetAliases(): void 51 | { 52 | $uom = new UnitOfMeasure( 53 | 'quatloos', 54 | function ($valueInNativeUnit) { 55 | return $valueInNativeUnit; 56 | }, 57 | function ($valueInThisUnit) { 58 | return $valueInThisUnit; 59 | } 60 | ); 61 | 62 | $uom->addAlias('ooltauqs'); 63 | $uom->addAlias('schmoos'); 64 | 65 | $this->assertEquals( 66 | ['ooltauqs', 'schmoos'], 67 | $uom->getAliases() 68 | ); 69 | } 70 | 71 | /** 72 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::addAlias 73 | */ 74 | public function testAddAliasWithNonStringAlias(): void 75 | { 76 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonStringUnitName::class); 77 | $uom = new UnitOfMeasure( 78 | 'quatloos', 79 | function ($valueInNativeUnit) { 80 | return $valueInNativeUnit; 81 | }, 82 | function ($valueInThisUnit) { 83 | return $valueInThisUnit; 84 | } 85 | ); 86 | 87 | $uom->addAlias(42); 88 | } 89 | 90 | /** 91 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::isAliasOf 92 | */ 93 | public function testIsAliasOf(): void 94 | { 95 | $uom = new UnitOfMeasure( 96 | 'quatloos', 97 | function ($valueInNativeUnit) { 98 | return $valueInNativeUnit; 99 | }, 100 | function ($valueInThisUnit) { 101 | return $valueInThisUnit; 102 | } 103 | ); 104 | 105 | $uom->addAlias('ooltauqs'); 106 | 107 | $this->assertTrue($uom->isAliasOf('ooltauqs')); 108 | } 109 | 110 | /** 111 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::isAliasOf 112 | */ 113 | public function testIsNotAliasOf(): void 114 | { 115 | $uom = new UnitOfMeasure( 116 | 'quatloos', 117 | function ($valueInNativeUnit) { 118 | return $valueInNativeUnit; 119 | }, 120 | function ($valueInThisUnit) { 121 | return $valueInThisUnit; 122 | } 123 | ); 124 | 125 | $uom->addAlias('ooltauqs'); 126 | 127 | $this->assertFalse($uom->isAliasOf('wampii')); 128 | } 129 | 130 | /** 131 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::isAliasOf 132 | * 133 | */ 134 | public function testIsAliasOfWithNonStringAlias(): void 135 | { 136 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonStringUnitName::class); 137 | $uom = new UnitOfMeasure( 138 | 'quatloos', 139 | function ($valueInNativeUnit) { 140 | return $valueInNativeUnit; 141 | }, 142 | function ($valueInThisUnit) { 143 | return $valueInThisUnit; 144 | } 145 | ); 146 | 147 | $uom->addAlias('ooltauqs'); 148 | 149 | $this->assertFalse($uom->isAliasOf(42)); 150 | } 151 | 152 | /** 153 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::convertValueFromNativeUnitOfMeasure 154 | */ 155 | public function testConvertValueFromNativeUnitOfMeasure(): void 156 | { 157 | $uom = new UnitOfMeasure( 158 | 'quatloos', 159 | function ($valueInNativeUnit) { 160 | return $valueInNativeUnit * 1.1234; 161 | }, 162 | function ($valueInThisUnit) { 163 | return false; 164 | } 165 | ); 166 | 167 | $this->assertSame(11.234, $uom->convertValueFromNativeUnitOfMeasure(10)); 168 | } 169 | 170 | /** 171 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::convertValueFromNativeUnitOfMeasure 172 | */ 173 | public function testConvertValueFromNativeUnitOfMeasureWithNonNumericalValue(): void 174 | { 175 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonNumericValue::class); 176 | $uom = new UnitOfMeasure( 177 | 'quatloos', 178 | function ($valueInNativeUnit) { 179 | return $valueInNativeUnit * 1.1234; 180 | }, 181 | function ($valueInThisUnit) { 182 | return false; 183 | } 184 | ); 185 | 186 | $this->assertSame(11.234, $uom->convertValueFromNativeUnitOfMeasure('string')); 187 | } 188 | 189 | /** 190 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::convertValueToNativeUnitOfMeasure 191 | */ 192 | public function testConvertValueToNativeUnitOfMeasure(): void 193 | { 194 | $uom = new UnitOfMeasure( 195 | 'quatloos', 196 | function ($valueInNativeUnit) { 197 | return false; 198 | }, 199 | function ($valueInThisUnit) { 200 | return $valueInThisUnit * 1.1234; 201 | } 202 | ); 203 | 204 | $this->assertSame(11.234, $uom->convertValueToNativeUnitOfMeasure(10)); 205 | } 206 | 207 | /** 208 | * @covers \PhpUnitsOfMeasure\UnitOfMeasure::convertValueToNativeUnitOfMeasure 209 | */ 210 | public function testConvertValueToNativeUnitOfMeasureWithNonNumericalValue(): void 211 | { 212 | $this->expectException(\PhpUnitsOfMeasure\Exception\NonNumericValue::class); 213 | $uom = new UnitOfMeasure( 214 | 'quatloos', 215 | function ($valueInNativeUnit) { 216 | return false; 217 | }, 218 | function ($valueInThisUnit) { 219 | return $valueInThisUnit * 1.1234; 220 | } 221 | ); 222 | 223 | $this->assertSame(11.234, $uom->convertValueToNativeUnitOfMeasure('string')); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /tests/phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | A basic coding standard. 5 | 6 | vendor/* 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tests/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | ./ 12 | 13 | 14 | 15 | 16 | 17 | ../source 18 | 19 | 20 | ../vendor 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------