bluesnowman/fphp-saber

一个功能性的PHP库,它推广强类型、不可变对象和惰性求值。

0.0.1 2015-01-02 00:12 UTC

This package is not auto-updated.

Last update: 2024-09-25 15:20:11 UTC


README

一个功能性的PHP库,它推广强类型、不可变对象和惰性求值。

License Latest Stable Version Build Status Dependency Status Code Coverage Issue Count Average time to resolve an issue Percentage of issues still open 更多...

要求

  • PHP 7.0+
  • 需要 mbstring 扩展或 iconv 扩展(仅当处理不同字符集时)。
  • 需要 gmp 扩展(仅当使用 IInteger\Type 时)。

装箱

要“装箱”PHP类型原语或对象,使用类的方法 make 创建相应数据类型的实例。此方法通过将值转换为正确的数据类型来强制类型。如果值无法转换为正确的数据类型,将抛出异常。

$object = IInt32\Type::make(7);

为了更好的性能,使用 box 方法以避免其对应的 make 方法在创建实例之前可能执行的不必要的预处理。

$object = IInt32\Type::box(7);

某些数据类型使用单例方法进行初始化。例如,IUnit\Type 类的初始化如下所示

$object = IUnit\Type::instance();

同样,其他数据类型有更具体的单例方法。其中之一是 ITrit 数据类型,它有三个单例方法用于负一、零和正一。

$negative = ITrit\Type::negative();
$zero = ITrit\Type::zero();
$positive = ITrit\Type::positive();

建议尽可能使用这些工厂/单例方法来初始化数据类型,而不是使用构造函数。这既是为了传统原因,也是为了实现原因。

要“取消装箱”一个装箱对象,请在相应的类上调用unbox方法以获取其值。

$value = $object->unbox();

流畅API

许多数据类型允许使用流畅API;因此,许多方法可以在一个语句中一起链接。通过使用PHP的神奇__call方法,某些数据类型可以像实例方法一样访问它们各自模块的方法。(模块中的方法定义方式类似于C#中扩展方法的定义。)例如,您可以执行以下操作

$object = IInt32\Type::box(7)->increment()->decrement();

此语句在功能上等同于编写

$object = IInt32\Module::decrement(IInt32\Module::increment(IInt32\Type::box(7)));

注意:此流畅API仅适用于返回Core\Type对象的方法。

Type类为特定类型定义了一个精简的接口。

Module类定义了一组用于处理其相应Type类的方发。所有方法都是静态的,并且必须为其第一个参数定义相应的Type类。

Utilities类定义了一组与其相应Type类相关的方发。所有方法都是静态的。

Iterator类定义了PHP如何通过迭代器计数和遍历集合。

方法

一般来说,不是以两个下划线开头的方法将返回一个装箱对象。

$object = IInt32\Type::box(7)->increment();

此规则的例外之一是unbox方法。

以两个下划线开头的方法将返回一个未装箱的值,这通常是一个PHP类型原始值或对象。这是通过PHP的神奇__call方法实现的。

$value = IInt32\Type::box(7)->__increment();

这基本上在功能上等同于编写

$value = IInt32\Type::box(7)->increment()->unbox();

变量

该库为某些变量采用了以下命名约定

$c通常表示一个携带的值。
$e通常表示一个异常。
$i$j$k通常表示一个索引或计数。
$n通常表示一个数量。
$p通常表示一个位置。
$r通常表示一个结果。

$x$y$z通常表示一个对象或一个值。
$xs$ys$zs通常分别表示$x$y$z对象/值的集合。
$xss$yss$zss通常分别表示$xs$ys$zs集合的集合。

$xi$yi$zi通常分别表示$x$y$z对象/值集合的迭代器。
$xsi$ysi$zsi通常分别表示$xs$ys$zs集合的迭代器。

可调用对象

$closure函数没有预定义的签名或返回类型;但作为一个一般规则,它应该利用Core\Type对象作为参数和返回类型。

function(?Core\Type... $m) : ?Core\Type

$operator函数用于找到对一个或多个操作数的操作符应用的结果。

function(Core\Type $c) : Core\Type
function(Core\Type $c, Core\Type $x) : Core\Type

$predicate函数用于找到执行布尔评估的结果。

function(Core\Type $x) : IBool\Type
function(Core\Type $x, IInt32\Type $i) : IBool\Type

$procedure函数用于执行不返回值的操作(尽管技术上PHP默认返回一个null值)。在逻辑上使用返回语句提前终止过程的情况下,返回值必须是null值或一个IUnit\Type对象。

function(Core\Type $x) : ?IUnit\Type
function(Core\Type $x, IInt32\Type $i) : ?IUnit\Type

$subroutine函数用于执行返回值的操作。

function(Core\Type $x) : Core\Type
function(Core\Type $x, IInt32\Type $i) : Core\Type

$tryblock函数用于处理可能抛出运行时异常的代码块。

function() : Core\Type

选择

对象可以通过使用when子句进行比较。当xy匹配时(即当$x->__eq($y)评估为true时),when子句会被满足。如果遇到匹配,将执行$procedure

$x = IInt32\Type::box(8);
$y = IInt32\Type::box(8);

Control\Type::choice($x)
	->when($y, function(IInt32\Type $x) {
		// passes, do something
	})
	->otherwise(function(IInt32\Type $x) {
		// skipped
	})
->end();

对象还可以通过使用unless子句进行比较。当xy都不匹配时(即当$x->__eq($y)评估为false时),unless子句会被满足。如果匹配结果为假,将执行$procedure

$x = IInt32\Type::box(8);
$y = IInt32\Type::box(7);

Control\Type::choice($x)
	->unless($y, function(IInt32\Type $x) {
		// passes, do something
	})
	->otherwise(function(IInt32\Type $x) {
		// skipped
	})
->end();

序列

可以通过以下方式轻松创建包含数字序列的列表:

$object = IInt32\Module::sequence(IInt32\Type::zero(), IInt32\Type::box(5));

这表示[0..5]。它将生成[0,1,2,3,4,5]。

您还可以生成如[0,2..10]的序列,它将生成[0,2,4,6,8,10]。

$object = IInt32\Module::sequence(IInt32\Type::zero(), ITuple\Type::box2(IInt32\Type::box(2), IInt32\Type::box(10)));

类似的函数也存在于IDouble、IFloat和IInteger中。

异常

要抛出异常,请执行以下操作:

$message = 'Hi, my name is :name';
$tokens = array(':name' => 'Blue Snowman');
$code = IInt32\Type::zero();
Control\Exception\Module::raise(new Throwable\UnexpectedValue\Exception(
    $message, // optional
    $tokens,  // optional
    $code     // optional
));

除了使用传统的try/catch语句外,您还可以使用内置的try_控制功能

$either = Control\Exception\Module::try_(function() {
	// do something that might cause an exception to be thrown
});

这将把结果包裹在IEither\Type中。按照惯例,异常将被包裹在IEither\Left\Type中,而成功的结果将被包裹在IEither\Right\Type中。

层次结构

以下描述了数据类型之间的关系

+ Core\Type
  + Control\Type
    + Choice\Type
  + Data\Type
    + IBool\Type
    + IChar\Type
    + ICollection\Type
      + IEither\Type
        + Left\Type
        + Right\Type
      + IMap\Type
        + IHashMap\Type
      + IOption\Type
        + Some\Type
        + None\Type
      + ISeq\Type
        + IArrayList\Type
        + ILinkedList\Type
        + IString\Type
      + ISet\Type
        + IHashSet\Type
      + ITuple\Type
    + INumber\Type
      + IFloating\Type : IFractional\Type
        + IDouble\Type : IReal\Type
        + IFloat\Type : IReal\Type
      + IIntegral\Type : IReal\Type
        + IInt32\Type
        + IInteger\Type
        + ITrit\Type
      + IRatio\Type : IFractional\Type
    + IObject\Type
    + IRegex\Type
    + IUnit\Type
  + Throwable\Runtime\Exception
    + Throwable\EmptyCollection\Exception
    + Throwable\InvalidArgument\Exception
    + Throwable\OutOfBounds\Exception
    + Throwable\Parse\Exception
    + Throwable\UnexpectedValue\Exception
    + Throwable\UnimplementedMethod\Exception
    + Throwable\Unknown\Exception

大多数数据类型都与一个模块相关联。

ICollection类型还有一个迭代器类,以便该类可以与PHP的foreach循环一起使用。因为这些迭代器类必须遵守PHP的IteratorCountable接口,所以这些类中的方法不一定遵守此库使用的所有约定(即一些非双下划线方法将返回PHP类型原始值而不是相应的Core\Type对象)。

单元测试

此库提供了一个方便的Makefile,用于安装、更新和卸载ComposerPHPUnit。同样,此Makefile也可以用来运行此库中包含的任何单元测试。

要运行此Makefile,请导航到硬盘中它所在的位置,然后输入以下命令中的任何一个:

安装Composer和PHPUnit

make install

更新Composer和PHPUnit

make update

卸载Composer和PHPUnit

make uninstall

运行所有单元测试

make unit-test

仅运行特定组的单元测试,例如

make unit-test GROUP=TypeTest

有关其他命令的更多信息,请参阅Makefile中的文档

拉取请求

帮助改进此库。如果您有错误修复、建议或改进,请提交包含任何适用测试用例的拉取请求。

许可证

版权所有 2014-2016 Blue Snowman

根据Apache许可证第2版(“许可证”)授权;除非您遵守许可证,否则不得使用此文件。您可以在以下位置获取许可证副本:

https://apache.ac.cn/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则根据许可证分发的软件按“原样”分发,不提供任何明示或暗示的保证或条件。有关许可证的具体语言规定权限和限制,请参阅许可证。