triplepoint / php-units-of-measure
Requires
- php: >=5.4.0
Requires (Dev)
- phpunit/phpunit: 4.8.*
- squizlabs/php_codesniffer: 2.2.*
Replaces
README
简介
这是一个PHP库,用于表示和转换物理单位。此库的实用性在于将物理量封装起来,这样您就不必跟踪它们所表示的单位。例如
use PhpUnitsOfMeasure\PhysicalQuantity\Length; $height = new Length(6.16, 'feet'); echo $height->toUnit('m'); // would print 1.87757, which is 6.16 feet in meters.
这种抽象使得您可以创建接受物理量的接口,而无需要求它们具有特定的单位。例如,此函数假设高度是一个特定单位(可能是英尺)的浮点数,因此不希望将其绑定到特定的度量单位
// Tied to a specific unit of measure function isTooTallToRideThisTrain( $height ) { return $height > 5; } // Calling the function requires that you first convert whatever quantity // you have into the expected units: isTooTallToRideThisTrain(2 / 0.3048);
而使用此库的版本允许高度以任何方便的单位提供
use PhpUnitsOfMeasure\PhysicalQuantity\Length; // Free to operate on lengths in any unit of measure function isTooTallToRideThisTrain( Length $height ) { return $height->toUnit('ft') > 5; } // Calling the function now allows any unit to be used: isTooTallToRideThisTrain( new Length(2, 'm') );
安装
最好通过Composer将此库包含在项目中。有关详细信息,请参阅Composer网站,并请参阅Packagist.org网站中的此库。
如果您愿意手动将此库作为依赖项包含到项目中,那么建议您使用符合PSR-4的PHP自动加载器。此项目根命名空间与其基本目录之间的映射关系为
- vendor命名空间'PhpUnitsOfMeasure'映射到库的基本目录'source/'
有关进一步说明,请参阅您的自动加载器文档。
项目标签和版本
此项目遵循语义版本控制2.0.0中规定的指南。一般来说,版本的形式为'X.Y.Z',而X的增加表示不兼容的主要更改。
如果您将此项目作为依赖项包含到您的项目中,并且正在使用诸如Composer之类的自动化依赖项管理工具,那么建议您将主要版本(X)进行“固定”,并允许只有'Y'(次要更改)和'Z'(错误修复)的变化。有关详细信息,请参阅您的依赖项管理器的文档。
使用
转换
如上例所示,此库的基本用法是表示物理量和在典型单位之间进行转换。例如
use PhpUnitsOfMeasure\PhysicalQuantity\Mass; $quantity = new Mass(6, 'lbs'); echo $quantity->toUnit('g');
还可以隐式地将量转换为字符串,这将显示其原始值
use PhpUnitsOfMeasure\PhysicalQuantity\Mass; $quantity = new Mass(6, 'pounds'); echo $quantity; // '6 lbs'
算术运算符
还支持加法和减法。物理量对象的值是不可变的,因此这些算术方法返回表示结果的新量对象
use PhpUnitsOfMeasure\PhysicalQuantity\Volume; $first = new Volume(6, 'liters'); $second = new Volume(6, 'cups'); $sum = $first->add($second); echo $sum; // 7.4195292 l $difference = $first->subtract($second); echo $difference; // 4.5804708 l
向现有物理量添加新的度量单位
偶尔,您需要向一个预存的物理量添加一个新的度量单位。
例如,假设在一个项目中您需要一个名为“cubits”的新长度度量单位。您有两个选择:您可以永久地将新的度量单位添加到\PhpUnitsOfMeasure\PhysicalQuantity\Length
类的新子类中(或者在适当的情况下直接添加到该类并提交一个pull请求以将其添加到上游),或者您可以在运行时临时添加该单位。
在运行时添加新的度量单位
要在运行时向现有物理量添加新的度量单位,您将这样做
use PhpUnitsOfMeasure\PhysicalQuantity\Length; use PhpUnitsOfMeasure\PhysicalQuantity\UnitOfMeasure; // It's ok to create objects with cubits before the new unit is registered, since // the conversion doesn't happen until an output method is called $length = new Length(14, 'cubits'); // Build a new Unit of Measure object which represents the new unit, and which // knows how to convert between the new unit and the quantity's native unit // (in this case, meters). $cubit = new UnitOfMeasure( // This is the official name of this unit - typically it's the standard // abbreviation 'cb', // The second parameter is a function that converts from the native unit // to this unit function ($valueInNativeUnit) { return $valueInNativeUnit / 0.4572; }, // The third parameter is a function that converts from this unit to the // native unit function ($valueInThisUnit) { return $valueInThisUnit * 0.4572; } ); // Any alias names for this unit can be added here, to make it easier to use // variations $cubit->addAlias('cubit'); $cubit->addAlias('cubits'); // Register the new unit of measure with the quantity class Length::addUnit($cubit); // Now that the unit is registered, you can cast the measurement to any other // measure of length echo $length->toUnit('feet'); // '21'
简写工厂方法
请注意,当创建UnitOfMeasure
实例时,有一些方便的静态工厂方法。第一个允许您创建具有从原生单位线性缩放因子的度量单位。也就是说,转换函数符合以下形式:'Value in the native unit of measure' = 'Value in this unit of measure' * F
,其中F
是缩放因子。
$megameter = UnitOfMeasure::linearUnitFactory('Mm', 1e6); $megameter->addAlias('Megameter'); $megameter->addAlias('Megametre'); Length::addUnit($megameter);
另一个方便的方法是上述缩放因子工厂方法的一个特例,其中缩放因子设置为正好1,并作为一个方便的方法来生成原生单位。所有物理量都必须有一个且仅有一个原生单位,因此此方法可能只会为每个物理量类调用一次。
$meter = UnitOfMeasure::nativeUnitFactory('m'); $meter->addAlias('meter'); $meter->addAlias('metre'); Length::addUnit($meter);
自动生成公制单位
对于使用公制系统的单位,有一个方便的特性可用于实现PhysicalQuantityInterface
的类,它可以自动从一个单位生成完整的公制单位系列。例如
namespace PhpUnitsOfMeasure\PhysicalQuantity; use PhpUnitsOfMeasure\AbstractPhysicalQuantity; use PhpUnitsOfMeasure\UnitOfMeasure; use PhpUnitsOfMeasure\HasSIUnitsTrait; class Mass extends AbstractPhysicalQuantity { use HasSIUnitsTrait; protected static $unitDefinitions; protected static function initialize() { // Kilogram $kilogram = UnitOfMeasure::nativeUnitFactory('kg'); $kilogram->addAlias('kilogram'); $kilogram->addAlias('kilograms'); static::addUnit($kilogram); static::addMissingSIPrefixedUnits( $kilogram, 1e-3, '%pg', [ '%Pgram', '%Pgrams', ] ); } }
在这里,我们正在生成质量的原生单位千克,像往常一样将其添加到物理量中,然后通过调用HasSIUnitsTrait
特性提供的静态方法addMissingSIPrefixedUnits()
来生成SI单位的系列。
值得注意的是,第二个参数(1e-3)表示,虽然千克是质量的原始单位,但千克和基本公制质量单位克之间存在1/1000的系数。对于秒或米等物理量,其原始单位也是公制前缀系统的基本单位,此系数将为1。
第三和第四个参数包含单位名称和备用别名的模板。替换字符串'%p'和'%P'用于表示缩写和长形式的公制前缀。例如,'%pg'将生成系列..., 'mg', 'cg', 'dg', 'g', ...
,而模板'%Pgram'将生成系列..., 'milligram', 'centigram', 'decigram', 'gram', ...
。
永久向物理量添加新的度量单位
以上添加新测量单位到物理量的示例允许您在PHP执行期间注册新单位,但一旦执行终止,这些单位就会丢失;每次您使用Length
测量并希望使用尺度时,都需要重复此过程。
可以通过与一次性示例基本相同的过程将新单位永久添加到物理量类中,只需在量类的initialize()方法内进行即可。例如
namespace PhpUnitsOfMeasure\PhysicalQuantity; use PhpUnitsOfMeasure\AbstractPhysicalQuantity; use PhpUnitsOfMeasure\UnitOfMeasure; class Length extends AbstractPhysicalQuantity { protected static $unitDefinitions; protected static function initialize() { // ... // ... // Here's all the pre-existing unit definitions for Length // ... // ... // Cubit $cubit = UnitOfMeasure::linearUnitFactory('cb', 0.4572); $cubit->addAlias('cubit'); $cubit->addAlias('cubits'); static::addUnit($cubit); } }
现在任何使用Length
的程序都将以已经内置的尺度单位开始。请注意,在这里我们使用了更简洁的线性单位工厂方法,但结果与上面使用的调用UnitOfMeasure
构造函数的展开形式等效。此外,注意我们使用了static
关键字而不是类名,尽管在这种情况下两种方式都可以接受。
添加新物理量
物理量是可测量值的类别,如质量、长度、力等。
对于本库中尚未存在的物理量,将需要编写一个类来支持新的物理量。所有物理量都实现了\PhpUnitsOfMeasure\PhysicalQuantityInterface
接口,通常扩展了\PhpUnitsOfMeasure\AbstractPhysicalQuantity
类,并且通常只有一个initialize()
方法,该方法创建量度单位。请参阅上面的典型物理量类示例以及如何向量类添加新单位。
请注意,每个物理量都有一个选定的“原生单位”,这通常是国际单位制(SI)标准。这个单位的主要作用是,所有其他单位都将转换到和从这个选定的原生单位转换。在编写新单位的新转换时,了解物理量的原生单位非常重要。
向现有单位添加新别名
可能会出现这样的情况,即给定的物理量存在所需的测量单位,但缺少该单位的别名。例如,如果您认为'footses'是长度单位'ft'明显缺少的别名,您可以通过以下方式临时添加该别名:
use PhpUnitsOfMeasure\PhysicalQuantity\Length; // It's ok to use footses here, since the conversion doesn't happen // until later $length = new Length(4, 'footses'); // Fetch the unit of measure object that represents the 'ft' unit $footUnit = Length::getUnit('ft'); // Any alias names for this unit can be added here, to make it easier // to use variations $footUnit->addAlias('footses'); // Now that the unit has been modified with its new alias, you can cast // the measurement to any other measure of length echo $length->toUnit('m'); // '1.2192'
当然,如果您需要永久添加别名,您可以在量类初始化()方法中这样做,如上所示。
测试和贡献
欢迎提交拉取请求,特别是关于新单位或新物理量的请求。但是,请注意,存在许多来源的转换系数,并且并非所有都小心地尊重已知精度。
在美国,计量标准机构是NIST,他们已经发布了NIST特别出版物1038“国际单位制(SI) - 通用转换系数”。本指南包含了各种单位与基本SI单位之间的批准转换系数。
此外,请注意,任何新的物理量都应选择适当的SI单位作为其原生单位。
拉取请求和合并
此存储库的工作流程如下
- 要开发新的贡献,请从主存储库的
master
分支进行分叉或分支。 - 拉取请求和贡献合并始终提交到主仓库的
master
分支 - 有时,
master
分支的提交会被标记,并发布新版本 - 目前,不支持维护旧项目版本的错误修复分支。如果需要,我们可以重新审视这个问题。
此仓库的最终用户应仅在生产环境中使用标记的提交。对当前“即将发布”的代码感兴趣的用户可以使用 master
,但应理解它可能会意外更改。所有其他现有分支(如果有)应被视为开发中的“功能”分支,尚未准备好使用。
本地测试环境
包含了一个适用于运行必要单元测试的 Vagrant 虚拟机配置。要启动虚拟机,请确保您已安装 Vagrant 和 Virtualbox,并从项目根目录
vagrant up
vagrant ssh
cd /project
为测试设置
虚拟机开发环境已经安装了 Composer。一旦您已通过 ssh 连接到虚拟机,请安装此项目的开发依赖项
rm -rf vendor composer.phar update --verbose --prefer-dist
单元测试
所有与本项目相关的测试都可以手动运行
vendor/bin/phpunit -c ./tests/phpunit.xml.dist ./tests
CodeSniffer
CodeSniffer 验证编码标准是否得到遵守。一旦项目用开发依赖项构建,您可以使用以下命令运行检查
vendor/bin/phpcs --encoding=utf-8 --extensions=php --standard=./tests/phpcs.xml -nsp ./
持续集成
上述测试会自动在 Travis-CI 上对 Github 提交执行。