wojciech.nawalaniec / phlambda
PHP 函数库,类似于 JS Rambda(https://github.com/ramda/ramda)。
Requires
- php: ^8
- ext-mbstring: *
Requires (Dev)
- infection/infection: ^0.25.5
- nette/php-generator: ^3.6
- phpunit/phpunit: ^9.5
README
PHP 的小型库,包含一系列有助于函数式编程的有用函数。
特性
- 一组有助于函数式编程的有用函数
- 所有函数都是自动柯里化的
- 每个数组都可以用特殊类包装,允许链式调用
- 第一个参数总是函数,要操作的数据是最后一个参数
目录
安装
要安装,请运行
composer require wojciech.nawalaniec/phlambda
使用方法
所有函数和常量都在一个命名空间中,因此它不会与项目中现有或其他库中的现有内容冲突。您可以简单地使用别名(为了简化)导入命名空间,如下所示
use Wojciech\Phlambda as f; f\all(f\above(2), [1, 2, 3, 4]);
您可以使用类似以下方式导入一个或多个函数
use function Wojciech\Phlambda\{all, above}; all(above(2), [1, 2, 3, 4]);
还有一些常量可以用于接受回调的地方,因为 PHP 将它们解析为函数
use function Wojciech\Phlambda\map; use const Wojciech\Phlambda\toString; map(toString, [1, 2, 3]);
如果您有一些数组并且希望对其进行多次、链式操作,则可以使用具有 _() 函数的特殊对象将其包装
use function Wojciech\Phlambda\{_, below, concat}; use const Wojciech\Phlambda\toString; _($someArray) ->filter(below(30)) ->map(toString) // you can use constant which will be resolved as callable by PHP ->reduce(concat(), ''); // or you can call function without params because all functions all curried
如果您希望代码更易于阅读,则可以使用该类的静态方法: Wrapper::wrap($array)。
如果您不想使用对象,则可以使用函数。包装器的方法只是那些函数的代理,并且仅用于链式调用的目的。
文档
柯里化
该库与 PHP 的其他函数库不同的地方在于所有函数都是自动柯里化的。如果您不知道柯里化函数是什么,让我试着解释一下。根据 维基百科
在数学和计算机科学中,柯里化是将接受多个参数的函数转换为一系列接受单个参数的函数的技术。
让我们看看一个例子
// we can use reduce function normally like this: $array = ['a', 'b', 'c']; $result = reduce(\Wojciech\Phlambda\concat, '', $array); // $result = 'abc' // and we can use it like currying function: $concat = reduce(\Wojciech\Phlambda\concat, ''); // now it will return callback accepting last param from reduce - an array $result = $concat($array); // $result = 'abc'
由于我决定实现柯里化,我还添加了占位符功能。占位符是您可以传递给柯里化函数的特殊类型,如果您想推迟传递某些参数。
占位符使用示例
$array = [1, 2, 3]; $reducer = reduce(__, __, $array); $sum = $reducer(sum, 0); $multiplication = $reducer(multiply, 0);
开发指南
工具
make build-docs- 生成 HTML 文档。 需要已安装 Dockermake generate-constants- 为所有函数生成src/constants.php文件
背景
PHP 并不是作为函数式编程语言设计的,这是我确定的一点。我们可以创建和使用匿名函数,在 7.4 中我们甚至得到了箭头函数 fn () =>。语言本身为我们提供了一些函数,如 array_map() 等,我们可以传递数组和一些可调用来对输入执行一些操作。但是它……太繁琐了。
有一天在公司里,我的朋友开了一个关于 PHP 的玩笑,说我们无法在 PHP 中做这样的事情
someArray.every(below(30));
我想了一会儿,回答说
function below(int $val): callable { return fn(int $v) => $v < $val; } function every(array $a, callable $fn): array { return array_filter($a, $fn); } $arr = [1, 2, 3, 4]; every($arr, below(3));
这两个例子很相似,但我们可以看到,使用PHP解决方案,我们无法链式调用方法,而且我们大多数时候必须自己编写那些方法。过了一段时间,我脑海中又闪现了一个想法。我们可以利用面向对象编程(OOP)创建一个实现了\ArrayAccess接口的类,这样它就可以被认为是类似数组的,并拥有所有可以链式调用的那些美好方法。我想到的是这样
$arrayObject ->filter(below(30)) ->sum();
这似乎是一个不错的周末项目,所以现在就来了。
JavaScript有一些非常棒的函数式库,但其中一个(由前面提到的朋友指出)似乎很有趣。它是Ramda。它很有趣,因为它自动实现了函数柯里化,这给那个项目增加了一些复杂性。