alphametric / strong-native-types
提供一组强类型类包装器,用于PHP的本地数据类型。
Requires
- php: ^7.2
Requires (Dev)
- phpunit/phpunit: ^8.0
This package is auto-updated.
Last update: 2020-02-17 10:07:45 UTC
README
此包提供了一组对象,将这些原生PHP数据类型(字符串、浮点数、整数和布尔值)包装为强类型实现。还包含了一组可空对象包装器,对应四种数据类型,因此您可以直接强制指定一个对象是否允许null。
背景
PHP一直朝着强类型的精神发展。截至PHP 7.4,我们现在有了强类型类属性、方法参数和返回类型。然而,缺失的主要项目是方法中的类型。这可能在未来的版本中实现,但类型强制的问题并未得到解决。例如,虽然您可以在方法签名中强制一个int参数,但在方法内部将其更改为string是没有阻止的。
通过切换到对象,PHP将阻止您进行这种类型的操作,除非您在对象上显式调用提供的转换方法。在我看来,这是朝着正确方向迈出的一步(假设您是强类型/不允许类型强制的支持者)。
注意事项
此方法的主要“问题”是性能。由于您现在正在使用对象而不是简单的数据类型,PHP需要做更多的工作。在这方面,任务将稍微慢一点完成。对于大多数应用程序,影响微乎其微(毫秒)。然而,对于性能至关重要的应用程序/每毫秒都很重要的应用程序,使用此包可能不是首选。
安装
使用composer引入此包
composer require alphametric/strong-native-types
创建
首先导入四种数据类型的类
use Alphametric\Strong\Types\FloatType; use Alphametric\Strong\Types\StringType; use Alphametric\Strong\Types\BooleanType; use Alphametric\Strong\Types\IntegerType;
如果您希望允许null值,则需要导入可空版本
use Alphametric\Strong\Types\NullableFloatType; use Alphametric\Strong\Types\NullableStringType; use Alphametric\Strong\Types\NullableBooleanType; use Alphametric\Strong\Types\NullableIntegerType;
在此阶段,您可以像使用任何其他对象一样使用它们,例如作为方法参数、类属性、变量等。
注意:在理想的世界里,类名不应该包含'Type'后缀,但在PHP 7中,'String'和'Float'变成了保留字。因此,必须添加后缀才能使编译生效。
要创建实例,请使用new关键字或包含的make工厂方法
$string = new StringType('hello'); $string = StringType::make('hello');
以上两种方法中,如果提供的参数类型不正确,都会抛出异常,例如。
$int = new IntegerType('hello'); // throws exception
您也可以传递相同对象类型的实例。当使用实用方法(例如将IntegerType添加到另一个中)时,这很有用。
$int = new IntegerType(IntegerType::make(3));
如果您提供不兼容的类型,PHP将抛出异常
$int = new IntegerType(StringType::make('hello')); // throws exception
转换
如果您想将不同数据类型转换为其他类型,例如将原生PHP float转换为StringType,应使用from工厂方法
$string = StringType::from(1.5); // '1.5'
在无法进行合理数据转换的情况下,将抛出异常,例如。
$bool = BooleanType::from('hello'); // throws exception
注意:您不能将可空类型转换为非空类型。为此,您需要将对象进行强制类型转换。请参阅下面的“强制类型转换”。
怪癖
该包的底层转换逻辑还试图解决PHP类型强制的一些独特怪癖。例如,在PHP中,将零转换为布尔值的结果是false
,而将负数转换为布尔值的结果是true
。
以下是包强制执行的“修复”摘要
输入类型 | 目标类型 | 备注 |
---|---|---|
String 或 StringType 或 NullableStringType |
BooleanType |
如果字符串不在(《true》、《false》、《0》或《1》),则抛出异常。当是《true》或《1》时为true 。当是《false》或《0》时为false |
String 或 StringType 或 NullableStringType |
FloatType |
如果字符串不满足is_numeric ,则抛出异常 |
String 或 StringType 或 NullableStringType |
IntegerType |
如果字符串不满足is_numeric ,则抛出异常。对值调用round (结果将《2.7》变为《3》,而不是《2》) |
Float 或 FloatType 或 NullableFloatType |
IntegerType |
对值调用round (结果将《2.7》变为《3》,而不是《2》) |
Float 或 FloatType 或 NullableFloatType |
BooleanType |
当输入值大于等于《1》时为true ,否则为false |
Int 或 IntegerType 或 NullableIntegerType |
BooleanType |
当输入值大于等于《1》时为true ,否则为false |
强制类型转换
如果您想将可空类型转换为非空类型,或者相反,请调用相应的强制类型转换方法
StringType::from('hello')->toNullable(); // NullableStringType NullableStringType::from('hello')->toNonNullable(); // StringType NullableStringType::from(null)->toNonNullable(); // Throws exception
不可变性
所有创建的类型都是不可变
的,允许您轻松创建新实例而不修改原始对象,例如。
$x = StringType::from('hello'); $y = $x->append('world'); // $x = 'hello' // $y = 'helloworld'
注意:在包的2.0版本之前,您可以在可变性和不可变性状态之间切换,然而经过进一步思考,这个特性已经被删除,现在只使用
不可变
类型。
提取
在某个时刻,您可能希望检索对象中的底层值。您可以使用value
方法来完成此操作
StringType::from('hello')->value(); // 'hello'
每种类型还实现了PHP的魔法__toString
方法,允许您在特定情况下或使用var_dump
等命令时跳过使用value
方法。在这些情况下,null
值将被返回为字符串'null'
,而其他值将通过strval
方法传递。
如果您想以不同的数据类型检索对象的值,可以使用to
方法
StringType::from('1.5')->toString(); // '1.5' StringType::from('1.5')->toInteger(); // 2 StringType::from('1.5')->toFloat(); // 1.5 StringType::from('1.5')->toBoolean(); // true
与转换方法一样,该包试图解决在转换为原生类型时PHP的一些怪癖
类型 | 方法 | 备注 |
---|---|---|
StringType 或 NullableStringType |
toBoolean |
如果字符串不在(《true》、《false》、《0》或《1》),则抛出异常。当是《true》或《1》时为true 。当是《false》或《0》时为false |
StringType 或 NullableStringType |
toInteger |
如果字符串不满足is_numeric ,则抛出异常。对值调用round (结果将《2.7》变为《3》,而不是《2》) |
StringType 或 NullableStringType |
toFloat |
如果字符串不满足is_numeric ,则抛出异常 |
FloatType 或 NullableFloatType |
toBoolean |
当输入值大于等于《1》时为true ,否则为false |
FloatType 或 NullableFloatType |
toInteger |
对值调用round (结果将《2.7》变为《3》,而不是《2》) |
IntegerType 或 NullableIntegerType |
toBoolean |
当输入值大于等于《1》时为true ,否则为false |
BooleanType 或 NullableBooleanType |
toString |
返回《true》或《false》 |
当处理可空类型时,当值为null
时,对象将自动回退到默认值。这些默认值分别预置为《''》、《0》、《0.0》和《false》对于《string》、《int》、《float》和《bool》,但是您可以通过提供方法参数来更改默认值
NullableStringType::from(null)->toString(); // '' NullableStringType::from(null)->toString('test'); // 'test' NullableStringType::from(null)->toFloat(1.5); // 1.5 NullableStringType::from(null)->toBoolean(true); // true NullableStringType::from(null)->toInteger(57); // 57
注意:如果您覆盖了默认值,则值必须与匹配的类型,例如对于《float》是《1.5》,否则将抛出异常。
辅助函数
该软件包包括一些有用的辅助方法来创建数据类型的实例。这些辅助方法将尝试使用 make
工厂直接创建类型。如果失败,它们将尝试使用 from
工厂进行转换。如果这也失败,将抛出异常。
$object = string('test'); // StringType $object = string('test', $nullable = true); // NullableStringType $object = float(1.4); // FloatType $object = float(null, $nullable = true); // NullableFloatType $object = boolean(true); // BooleanType $object = boolean(false, $nullable = true); // NullableBooleanType $object = integer(5); // IntegerType $object = integer(9, $nullable = true); // NullableIntegerType
辅助方法
由于数据类型现在是对象,可以给它们添加行为。该软件包添加了大量的方法,其中许多是可链式的,允许您使用流畅的 API 修改底层数据。
类型 | 方法 | 备注 |
---|---|---|
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
add |
添加一个值 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
subtract |
减去一个值 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
divideBy |
除以一个值 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
multiplyBy |
乘以一个值 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
remainderFrom |
除以一个值并获取余数 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
modulusFrom |
余数的别名 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
between |
检查数字是否在两个数字之间 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
greaterThan |
检查数字是否大于另一个数字 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
greaterThenOrEqualTo |
检查数字是否大于或等于另一个数字 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
lessThan |
检查数字是否小于另一个数字 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
lessThanOrEqualTo |
检查数字是否小于或等于另一个数字 |
IntegerType 或 NullableIntegerType 或 FloatType 或 NullableFloatType |
random |
创建一个介于最小值和最大值之间的随机数 |
FloatType 或 NullableFloatType |
ceiling |
ceil 方法的包装器 |
FloatType 或 NullableFloatType |
floor |
floor 方法的包装器 |
FloatType 或 NullableFloatType |
round |
round 方法的包装器 |
FloatType 或 NullableFloatType |
roundUp |
使用 PHP_ROUND_HALF_UP 的 round 方法的包装器 |
FloatType 或 NullableFloatType |
roundDown |
使用 PHP_ROUND_HALF_DOWN 的 round 方法的包装器 |
FloatType 或 NullableFloatType |
roundEven |
使用 PHP_ROUND_HALF_EVEN 的 round 方法的包装器 |
FloatType 或 NullableFloatType |
roundOdd |
使用 PHP_ROUND_HALF_ODD 的 round 方法的包装器 |
BooleanType 或 NullableBooleanType |
isTrue |
检查布尔值是否为真 |
BooleanType 或 NullableBooleanType |
isFalse |
检查布尔值是否为假 |
BooleanType 或 NullableBooleanType |
true |
将布尔值设置为真 |
BooleanType 或 NullableBooleanType |
false |
将布尔值设置为假 |
StringType 或 NullableStringType |
after |
删除给定值之前的字符 |
StringType 或 NullableStringType |
append |
向字符串添加字符 |
StringType 或 NullableStringType |
before |
删除给定值之后的字符 |
StringType 或 NullableStringType |
contains |
检查值是否存在于字符串中 |
StringType 或 NullableStringType |
camelCase |
将字符串转换为驼峰式 |
StringType 或 NullableStringType |
capitalize |
ucwords 方法的包装器 |
StringType 或 NullableStringType |
capitalizeFirstLetter |
ucfirst 方法的包装器 |
StringType 或 NullableStringType |
endsWith |
检查字符串是否以给定值结束 |
StringType 或 NullableStringType |
explode |
explode 方法的包装器 |
StringType 或 NullableStringType |
findIndex |
strpos 方法的包装器 |
StringType 或 NullableStringType |
findLastIndex |
strrpos 方法的包装器 |
StringType 或 NullableStringType |
implode |
implode 方法的包装器 |
StringType 或 NullableStringType |
insert |
将值插入字符串的索引位置 |
StringType 或 NullableStringType |
kebabCase |
将字符串转换为短横线分隔式 |
StringType 或 NullableStringType |
length |
strlen 方法的包装器 |
StringType 或 NullableStringType |
limit |
限制字符串为给定的字符数 |
StringType 或 NullableStringType |
lowerCase |
将字符串转换为小写 |
StringType 或 NullableStringType |
lowerCaseFirstLetter |
lcfirst 方法的包装器 |
StringType 或 NullableStringType |
matches |
检查字符串是否与给定的正则表达式匹配 |
StringType 或 NullableStringType |
prepend |
将字符添加到字符串的开头 |
StringType 或 NullableStringType |
random |
生成指定长度的随机字符串 |
StringType 或 NullableStringType |
replace |
str_replace 方法的包装器 |
StringType 或 NullableStringType |
replaceFirst |
substr_replace 方法的包装器 |
StringType 或 NullableStringType |
replaceLast |
substr_replace 方法的包装器 |
StringType 或 NullableStringType |
replaceUsingExpression |
preg_replace 方法的包装器 |
StringType 或 NullableStringType |
safeHtml |
htmlspecialchars 方法的包装器 |
StringType 或 NullableStringType |
snakeCase |
将字符串转换为蛇形小写 |
StringType 或 NullableStringType |
studCase |
将字符串转换为花名册大写 |
StringType 或 NullableStringType |
substring |
mb_substr 方法的包装器 |
StringType 或 NullableStringType |
titleCase |
将字符串转换为标题大小写 |
StringType 或 NullableStringType |
trim |
《trim》方法包装器 |
StringType 或 NullableStringType |
trimLeft |
《ltrim》方法包装器 |
StringType 或 NullableStringType |
trimRight |
《rtrim》方法包装器 |
StringType 或 NullableStringType |
upperCase |
将字符串转换为大写 |
这些实用方法将强制执行原始数据类型/在结果会改变类型时抛出异常,例如将一个int
除以2.3
。
自定义方法(宏)
每种类型还包括一个特性,允许您添加自己的自定义实用方法,而无需创建子类。您可以使用闭包如下定义这些方法
// Register the macro StringType::macro('suffix', function($suffix) { return $this->value().' '.$suffix; }); // Call the method as normal StringType::make('Hello')->suffix('World') // Hello World
避免过度设计
常识会告诉你,如果你不打算进行任何形式的处理/数据操作,那么仅仅为了强制类型安全而将简单原生类型转换为对象几乎毫无意义。例如,考虑以下异常构造函数提供的string
throw new Exception('Something went wrong');
由于它不会被操作,并且不会对其进行处理,因此以下操作没有好处
throw new Exception(StringType::make('Something went wrong') -> value());
许可证
MIT许可证(MIT)。请参阅许可证文件以获取更多信息。