|
| 1 | +# Php Unit Conversion |
| 2 | + |
| 3 | +The `php-unit-conversion/php-unit-conversion` package provides full PSR-4 compatible unit conversion. Most other packages that are available for unit conversion are using `string` types to indicate unit types. In this package all unit types are classes. |
| 4 | + |
| 5 | +### Basic Usage |
| 6 | +```php |
| 7 | +use PhpUnitConversion\Unit\Mass; |
| 8 | +$milliGram = new Mass\MilliGram(12); |
| 9 | +$milliGram->getValue(); // 12 |
| 10 | +$milliGram->getSymbol(); // 'mg' |
| 11 | + |
| 12 | +/* A format method is available that accepts two parameters: |
| 13 | + * @integer precision |
| 14 | + * @boolean add_symbol |
| 15 | + */ |
| 16 | +$milliGram->format(3, false); // 12.000 |
| 17 | + |
| 18 | +/* Units are set relative to the BASE_UNIT of the unit type |
| 19 | + * e.g. for Mass the base unit is gram's |
| 20 | + */ |
| 21 | +echo Mass::BASE_UNIT; |
| 22 | +// PhpUnitConversion\Unit\Mass\Gram |
| 23 | + |
| 24 | +/* Most units are linear related to the base unit by a fixed factor |
| 25 | + * For these units you can retrieve the factor by calling getFactor, |
| 26 | + * this can return false if no factor has been defined |
| 27 | + */ |
| 28 | +echo $milliGram->getFactor(); |
| 29 | +// 0.001 |
| 30 | + |
| 31 | +/* The base unit has no factor defined, this is because we use class constants |
| 32 | + * to define factors for SI prefixes and you can't extend/overwrite constants |
| 33 | + */ |
| 34 | +var_dump((new Mass\Gram(2))->getFactor()); |
| 35 | +// false |
| 36 | +``` |
| 37 | + |
| 38 | +### Unit Conversions |
| 39 | +```php |
| 40 | +use PhpUnitConversion\Unit; |
| 41 | +use PhpUnitConversion\Unit\Mass; |
| 42 | + |
| 43 | +/* If you have an instantiated unit, you can convert to a new unit by calling the static `from` method on the unit you want to convert to |
| 44 | + */ |
| 45 | +$grams = new Mass\Gram(21); |
| 46 | +echo Mass\PennyWeight::from($grams)->format(); |
| 47 | +// 13.503 dwt |
| 48 | + |
| 49 | +/* You can also call the `to` method on the unit object and pass the class name of the unit you want to convert to |
| 50 | + */ |
| 51 | +$grams = new Mass\Gram(21); |
| 52 | +$milliGram = $massUnit->to(Mass\MilliGram::class); |
| 53 | +echo $milliGram->format(0); |
| 54 | +// 21000 mg |
| 55 | + |
| 56 | +/* or use an instantiated object, this will overwrite any existing value |
| 57 | + * due to php passing objects by reference there is no need for a left assignment this way |
| 58 | + */ |
| 59 | +$grams = new Mass\Gram(21); |
| 60 | +$kiloGram = new Mass\KiloGram; |
| 61 | +$grams->to($kiloGram); |
| 62 | +echo $kiloGram->format(); |
| 63 | +// 0.021 kg |
| 64 | + |
| 65 | +/* but `to` also returns the object |
| 66 | +$massUnit = new Mass\Gram(21); |
| 67 | +$ounce = $massUnit->to(new Mass\Ounce); |
| 68 | +echo $ounce->format(); |
| 69 | +// 0.741 oz |
| 70 | + |
| 71 | +/* you can convert directly from a string which has a format of '<value><symbol>' |
| 72 | + * by calling the static `from` method on the unit class |
| 73 | + */ |
| 74 | +$milliGrams = Unit::from('21 mg'); |
| 75 | +var_dump($milliGrams instanceof Mass\MilliGram::class) |
| 76 | +// true |
| 77 | + |
| 78 | +/* but if you already know which type of unit to expect, you can also call |
| 79 | + * `from` directly on the unit type class. This could prevent errors when multiple units |
| 80 | + * exists with the same symbol |
| 81 | + */ |
| 82 | +$milliGrams = Mass::from('21 mg'); |
| 83 | +var_dump($milliGrams instanceof Mass\MilliGram::class) |
| 84 | +// true |
| 85 | +``` |
| 86 | + |
| 87 | +### Arithmetic Operators |
| 88 | +```php |
| 89 | +/* You can add units of the same type by calling `add` method with one or more units as arguments |
| 90 | + * add always returns a new instance |
| 91 | + */ |
| 92 | +$grams = new Mass\Gram(580); |
| 93 | +$addGrams = $massUnit->add(new Mass\KiloGram(0.4), new Mass\Gram(11)); |
| 94 | +echo $addGrams->format(0); |
| 95 | +// 991 g |
| 96 | + |
| 97 | +/* You can also substract units of the same type by calling `substract` method with one or more units as arguments |
| 98 | + * substract always returns a new instance |
| 99 | + */ |
| 100 | +$grams = new Mass\Gram(580); |
| 101 | +$subGrams = $massUnit->substract(new Mass\KiloGram(0.4), new Mass\Gram(11)); |
| 102 | +echo $subGrams->format(0); |
| 103 | +// 169 g |
| 104 | + |
| 105 | +/* When you try to add/substract units of different types an exception is thrown |
| 106 | + */ |
| 107 | +$grams = new Mass\Gram(580); |
| 108 | +$addGrams = $massUnit->add(new Time\Second(60) ); |
| 109 | +// throws a PhpUnitConversion\Exception\UnsupportedUnitException |
| 110 | +``` |
| 111 | + |
| 112 | +### Contributing |
| 113 | +As this package is still very much a work in progress, any help adding more unit's and unit tests is really appreciated! |
| 114 | + |
| 115 | +A couple of things important when submitting a Pull Request: |
| 116 | +- ** Use the PSR-2 Coding Standard ** |
| 117 | +- ** Add tests ** |
| 118 | +- ** Use the method of implementation as described below ** |
| 119 | + |
| 120 | +#### Implementation |
| 121 | +##### Add a new unit type |
| 122 | +Please make sure to first define a `TYPE_XXX` const in `Unit.php`. Give it a unique number, prefereable the next in the sequence. |
| 123 | + |
| 124 | +Next create a new unit type class in file `Unit/XXX.php`, this will hold the type description. All units belonging to this unit type |
| 125 | +should be extended from this class. Make sure you add `const TYPE = Unit::TYPE_XXX`. Also set the const BASE_UNIT to the class of your |
| 126 | +base unit. Please choose your base unit logically, units from the metric system have preference over the imperial / usc systems. |
| 127 | + |
| 128 | +Now create a folder Unit/XXX/ in which we will place all the unit classes for this unit type, after this proceed with adding a base unit |
| 129 | + |
| 130 | +##### Adding a base unit |
| 131 | +We prefer the base unit to be a unit from the metric system. This way we can easily add all SI prefixed units by extending them from the base |
| 132 | +unit and only implement a PhpUnitConversion\Prefix\Metric\<SI_Prefix> interface. E.g. the implementation of Mass\MilliGram is: |
| 133 | +```php |
| 134 | +class MilliGram extends Gram implements Metric, Milli |
| 135 | +{ |
| 136 | +} |
| 137 | +``` |
| 138 | +See the comment above in Basic Usage about the FACTOR constant. You should not set a FACTOR on the `BASE_UNIT`, otherwise the above implementation |
| 139 | +will fail because the interface `Prefix\Metric\Milli` cannot overwrite an already defined class constant. |
| 140 | + |
| 141 | +See the `Gruntfile.js` file for a way to quickly add all prefixed classes to your unit. |
| 142 | + |
| 143 | +##### Add an new unit to a unit type |
| 144 | +When adding a unit `YYY` to unit type `XXX` start by creating the file `Unit/XXX/YYY.php`. |
| 145 | + |
| 146 | +If your unit has a linear correspondence to the base unit, just set class constant `FACTOR` to its correct value. |
| 147 | +If your unit has an offset to the base unit, you can add a class constant `ADDITION`. |
| 148 | +(Conversion to the BASE_UNIT value is done by first applying the `FACTOR`, then adding the `ADDITION`) |
| 149 | + |
| 150 | +Please also set the class constant `SYMBOL` and `LABEL`. When your unit does not have a `SYMBOL`, omit it or set it to an empty string. `LABEL` is often equal to your lower case classname. |
| 151 | + |
| 152 | +##### Relative factors |
| 153 | +It is possible to set factors on your unit which are not relative to the `BASE_UNIT` but to another unit. You should extend your new unit `ZZZ` from |
| 154 | +the existing unit `YYY` and include the `HasRelativeFactor` Trait in `ZZZ`. Due to class scopes in php you also have to add the `HasFactor` trait to |
| 155 | +`YYY` to make sure we use the correct (late binding) static class constant. |
| 156 | + |
| 157 | +See `Unit\Mass\Pound` (=`YYY`) and `Unit\Mass\Ounce` (=`ZZZ`) for an example: |
| 158 | +```php |
| 159 | +class AvoirdupoisPound extends Mass |
| 160 | +{ |
| 161 | + use HasFactor; |
| 162 | + |
| 163 | + const FACTOR = 453.59237; // FACTOR is relative to Mass\Gram, 453.6 Gram in a Pound |
| 164 | +} |
| 165 | + |
| 166 | +class Ounce extends Pound |
| 167 | +{ |
| 168 | + use HasRelativeFactor; |
| 169 | + |
| 170 | + const FACTOR = 16; // FACTOR is relative to Mass\Pound, 16 Ounce in a Pound |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +##### System of Measurement |
| 175 | +Please also implement the correct unit system interfaces for your unit: |
| 176 | +```php |
| 177 | +/* Metric units should implement the Metric interface |
| 178 | + * see https://en.wikipedia.org/wiki/Metric_system |
| 179 | + */ |
| 180 | +use PhpUnitConversion\System\Metric; |
| 181 | + |
| 182 | +class YYY extends XXX implements Metric |
| 183 | +{ |
| 184 | + |
| 185 | +/* Imperial units should implement the Imperial interface |
| 186 | + * see https://en.wikipedia.org/wiki/Imperial_units |
| 187 | + */ |
| 188 | +use PhpUnitConversion\System\Imperial; |
| 189 | + |
| 190 | +/* US customary units should implement the USC interface |
| 191 | + * see https://en.wikipedia.org/wiki/United_States_customary_units |
| 192 | + */ |
| 193 | +use PhpUnitConversion\System\USC; |
| 194 | + |
| 195 | +/* Some units like `feet` are used in more then one system, |
| 196 | + * in that case implement both systems |
| 197 | + */ |
| 198 | +use PhpUnitConversion\System\Imperial; |
| 199 | +use PhpUnitConversion\System\USC; |
| 200 | + |
| 201 | +class Yard extends InternationalYard implements Imperial, USC |
| 202 | +{ |
| 203 | +``` |
0 commit comments