alphametric/strong-native-types

此包已被废弃,不再维护。未建议替代包。

提供一组强类型类包装器,用于PHP的本地数据类型。

v2.0 2019-05-03 10:10 UTC

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

以下是包强制执行的“修复”摘要

输入类型 目标类型 备注
StringStringTypeNullableStringType BooleanType 如果字符串不在(《true》、《false》、《0》或《1》),则抛出异常。当是《true》或《1》时为true。当是《false》或《0》时为false
StringStringTypeNullableStringType FloatType 如果字符串不满足is_numeric,则抛出异常
StringStringTypeNullableStringType IntegerType 如果字符串不满足is_numeric,则抛出异常。对值调用round(结果将《2.7》变为《3》,而不是《2》)
FloatFloatTypeNullableFloatType IntegerType 对值调用round(结果将《2.7》变为《3》,而不是《2》)
FloatFloatTypeNullableFloatType BooleanType 当输入值大于等于《1》时为true,否则为false
IntIntegerTypeNullableIntegerType 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的一些怪癖

类型 方法 备注
StringTypeNullableStringType toBoolean 如果字符串不在(《true》、《false》、《0》或《1》),则抛出异常。当是《true》或《1》时为true。当是《false》或《0》时为false
StringTypeNullableStringType toInteger 如果字符串不满足is_numeric,则抛出异常。对值调用round(结果将《2.7》变为《3》,而不是《2》)
StringTypeNullableStringType toFloat 如果字符串不满足is_numeric,则抛出异常
FloatTypeNullableFloatType toBoolean 当输入值大于等于《1》时为true,否则为false
FloatTypeNullableFloatType toInteger 对值调用round(结果将《2.7》变为《3》,而不是《2》)
IntegerTypeNullableIntegerType toBoolean 当输入值大于等于《1》时为true,否则为false
BooleanTypeNullableBooleanType 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 修改底层数据。

类型 方法 备注
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType add 添加一个值
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType subtract 减去一个值
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType divideBy 除以一个值
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType multiplyBy 乘以一个值
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType remainderFrom 除以一个值并获取余数
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType modulusFrom 余数的别名
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType between 检查数字是否在两个数字之间
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType greaterThan 检查数字是否大于另一个数字
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType greaterThenOrEqualTo 检查数字是否大于或等于另一个数字
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType lessThan 检查数字是否小于另一个数字
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType lessThanOrEqualTo 检查数字是否小于或等于另一个数字
IntegerTypeNullableIntegerTypeFloatTypeNullableFloatType random 创建一个介于最小值和最大值之间的随机数
FloatTypeNullableFloatType ceiling ceil 方法的包装器
FloatTypeNullableFloatType floor floor 方法的包装器
FloatTypeNullableFloatType round round 方法的包装器
FloatTypeNullableFloatType roundUp 使用 PHP_ROUND_HALF_UPround 方法的包装器
FloatTypeNullableFloatType roundDown 使用 PHP_ROUND_HALF_DOWNround 方法的包装器
FloatTypeNullableFloatType roundEven 使用 PHP_ROUND_HALF_EVENround 方法的包装器
FloatTypeNullableFloatType roundOdd 使用 PHP_ROUND_HALF_ODDround 方法的包装器
BooleanTypeNullableBooleanType isTrue 检查布尔值是否为真
BooleanTypeNullableBooleanType isFalse 检查布尔值是否为假
BooleanTypeNullableBooleanType true 将布尔值设置为真
BooleanTypeNullableBooleanType false 将布尔值设置为假
StringTypeNullableStringType after 删除给定值之前的字符
StringTypeNullableStringType append 向字符串添加字符
StringTypeNullableStringType before 删除给定值之后的字符
StringTypeNullableStringType contains 检查值是否存在于字符串中
StringTypeNullableStringType camelCase 将字符串转换为驼峰式
StringTypeNullableStringType capitalize ucwords 方法的包装器
StringTypeNullableStringType capitalizeFirstLetter ucfirst 方法的包装器
StringTypeNullableStringType endsWith 检查字符串是否以给定值结束
StringTypeNullableStringType explode explode 方法的包装器
StringTypeNullableStringType findIndex strpos 方法的包装器
StringTypeNullableStringType findLastIndex strrpos 方法的包装器
StringTypeNullableStringType implode implode 方法的包装器
StringTypeNullableStringType insert 将值插入字符串的索引位置
StringTypeNullableStringType kebabCase 将字符串转换为短横线分隔式
StringTypeNullableStringType length strlen 方法的包装器
StringTypeNullableStringType limit 限制字符串为给定的字符数
StringTypeNullableStringType lowerCase 将字符串转换为小写
StringTypeNullableStringType lowerCaseFirstLetter lcfirst 方法的包装器
StringTypeNullableStringType matches 检查字符串是否与给定的正则表达式匹配
StringTypeNullableStringType prepend 将字符添加到字符串的开头
StringTypeNullableStringType random 生成指定长度的随机字符串
StringTypeNullableStringType replace str_replace 方法的包装器
StringTypeNullableStringType replaceFirst substr_replace 方法的包装器
StringTypeNullableStringType replaceLast substr_replace 方法的包装器
StringTypeNullableStringType replaceUsingExpression preg_replace 方法的包装器
StringTypeNullableStringType safeHtml htmlspecialchars 方法的包装器
StringTypeNullableStringType snakeCase 将字符串转换为蛇形小写
StringTypeNullableStringType studCase 将字符串转换为花名册大写
StringTypeNullableStringType substring mb_substr 方法的包装器
StringTypeNullableStringType titleCase 将字符串转换为标题大小写
StringTypeNullableStringType trim 《trim》方法包装器
StringTypeNullableStringType trimLeft 《ltrim》方法包装器
StringTypeNullableStringType trimRight 《rtrim》方法包装器
StringTypeNullableStringType 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)。请参阅许可证文件以获取更多信息。