Requires
- php: ~7.1
Requires (Dev)
- phpunit/phpunit: ^6.2
- satooshi/php-coveralls: ^1.0.2
- squizlabs/php_codesniffer: ^3.0
This package is auto-updated.
Last update: 2024-01-29 03:07:18 UTC
README
此库提供编写更功能化的PHP代码的工具。其简洁且一致的API让您以不同的方式提高生产力
目录
关于
编写此库是为了解决几个问题
- 为PHP中不同的可迭代类型和各个类型可用的不同操作提供一个单一、一致的API:一个API,任何可迭代,总是关联的,访问键。
- 提供PHP中尚未存在的可迭代处理操作。
- 使编写闭包变得快速且简单。可以使用谓词工厂生成常见(过滤)条件。
- 允许开发人员使用可选值类型轻松区分不同的函数输出。这些类型可用于解决类似
json_decode()
的问题,它在出错时返回NULL
,或者在成功解码JSON字符串null
时。没有额外的代码,如可选类型,无法区分不同的结果。 - 尽可能使用原生PHP特性以提高互操作性和性能。命名和参数顺序遵循PHP中的主要约定。这意味着所有迭代器都实现
\Iterator
,并且内部使用了许多PHP核心函数。 - 尽可能添加惰性,因此许多操作仅在您实际使用的迭代器项上应用。
安装
在您的项目根目录中运行composer require bartfeenstra/fu
。
用法
要使用任何代码,您必须首先在文件顶部导入命名空间
<?php use BartFeenstra\Functional as F; use BartFeenstra\Functional\Iterable as I; use BartFeenstra\Functional\Predicate as P; use function BartFeenstra\Functional\Iterable\iter; ?>
迭代器
可遍历/可迭代的数据结构可以转换为通用迭代器
<?php // Arrays. $iterator = iter([3, 1, 4]); // \Traversable (includes native/Spl iterators). $iterator = iter(new \ArrayIterator([3, 1, 4])); // Callables that (return callables that...) return iterators. $callable = function (){ return function () { return iter([]); }; }; $iterator = iter($callable); // Existing universal iterators are passed through. $iterator = iter([]); assert($iterator === iter($iterator)); // Objects can expose universal iterators as well. $toIterator = new class() implements I\ToIterator { public function iter(): I\Iterator { return iter([]); } }; $iterator = iter($toIterator); ?>
操作
以下操作与迭代器值一起工作,在用户提供的回调的情况下甚至包括键
each
为每个值执行代码。
<?php $carrier = []; $list = [3, 1, 4]; iter($list)->each(function (int $i) use (&$carrier) { $carrier[] = $i; }); assert($list === $carrier); ?>
filter
过滤掉不匹配的值。
<?php $result = iter([3, 1, 4])->filter(P\gt(2)); assert([0 => 3, 2 => 4] === $result->toArray()); ?>
find
尝试找到单个匹配的值。
<?php $found = iter([3, 1, 4, 1, 5, 9])->find(P\gt(4)); assert(new I\SomeItem(5, 4) == $found); ?>
map
逐个转换所有值。
<?php $original = [3, 1, 4]; $expected = [9, 3, 12]; $result = iter($original)->map(function (int $i): int { return 3 * $i; }); assert($expected === $result->toArray()); ?>
mapKeys
逐个转换所有键。
<?php $original = [ 3 => 'c', 1 => 'a', 4 => 'd', ]; $expected = [ 9 => 'c', 3 => 'a', 12 => 'd', ]; $result = iter($original)->mapKeys(function (string $value, int $key): int { return 3 * $key; }); assert($expected === $result->toArray()); ?>
reduce
将所有值合并成一个。
<?php $list = [3, 1, 4]; $sum = iter($list)->reduce(function (int $sum, int $item): int { return $sum + $item; }); assert(new F\SomeValue(8) == $sum); ?>
在处理完所有项目之前终止合并,抛出带有最终载体的TerminateReduction
。
fold
将所有值合并成一个,带有默认起始值。
<?php $start = 2; $list = [3, 1, 4]; $total = iter($list)->fold(function (int $total, int $item): int { return $total + $item; }, $start); assert(10 === $total); ?>
在处理完所有项目之前终止合并,抛出带有最终载体的TerminateFold
。
take
取n个值。
<?php $start = 2; $list = [3, 1, 4, 1, 5, 9]; $result = iter($list)->take(4); assert([3, 1, 4, 1] === $result->toArray()); ?>
takeWhile
尽可能从开始取连续匹配的值。
<?php $start = 2; $list = [3, 1, 4, 1, 5, 9]; $result = iter($list)->takeWhile(P\le(3)); assert([3, 1] === $result->toArray()); ?>
slice
将值切割成更小的集合。
<?php $start = 2; $list = [3, 1, 4, 1, 5, 9]; $result = iter($list)->slice(2, 3); assert([2 => 4, 3 => 1, 4 => 5] === $result->toArray()); ?>
min
获取最小值。
<?php $list = [3, 1, 4, 1, 5, 9]; $min = iter($list)->min(); assert(new F\SomeValue(1) == $min); ?>
max
获取最大值。
<?php $list = [3, 1, 4, 1, 5, 9]; $max = iter($list)->max(); assert(new F\SomeValue(9) == $max); ?>
sum
求所有值的和。
<?php $list = [3, 1, 4, 1, 5, 9]; $sum = iter($list)->sum(); assert(new F\SomeValue(23) == $sum); ?>
forever
无限重复值的集合。
<?php $list = [3, 1, 4]; $iterator = iter($list)->forever(); $expected = [3, 1, 4, 3, 1, 4, 3]; assert($expected === iterator_to_array($iterator->take(7), false)); ?>
zip
将两个或更多可迭代的值合并成元组。
<?php $one = [3, 1, 4]; $two = [1, 5, 9]; $three = [2, 9, 2]; $zip = iter($one)->zip($two, $three); $expected = [[3, 1, 2], [1, 5, 9], [4, 9, 2]]; assert($expected === iterator_to_array($zip)); ?>
list
将所有键转换为整数,从0开始。
<?php $array = [ 'a' => 'A', 'b' => 'B', 'c' => 'C', ]; $indexed = iter($array)->list(); $expected = ['A', 'B', 'C']; assert($expected === iterator_to_array($indexed)); ?>
listKeys
使用键作为值,并从0开始索引。
<?php $array = [ 'a' => 'A', 'b' => 'B', 'c' => 'C', ]; $keys = iter($array)->listKeys(); $expected = ['a', 'b', 'c']; assert($expected === iterator_to_array($keys)); ?>
flip
交换键和值,类似于array_flip()
。
<?php $array = [ 'a' => 3, 'b' => 1, 'c' => 4, ]; $flipped = iter($array)->flip(); $expected = [ 3 => 'a', 1 => 'b', 4 => 'c', ]; assert($expected === $flipped->toArray()); ?>
reverse
反转值的顺序。
<?php $array = [3, 1, 4]; $reverse = iter($array)->reverse(); assert([4, 1, 3] === $reverse->toArray()); ?>
first
获取第一个值。
<?php $array = [3, 1, 4, 1, 5, 9]; assert(new I\SomeItem(3, 0) == iter($array)->first()); ?>
last
获取最后一个值。
<?php $array = [3, 1, 4, 1, 5, 9]; assert(new I\SomeItem(9, 5) == iter($array)->last()); ?>
empty
检查是否存在值。
<?php assert(TRUE === iter([])->empty()); assert(FALSE === iter([3, 1, 4])->empty()); ?>
sort
按值对项进行排序。
<?php $array = [ 3 => 'c', 1 => 'a', 4 => 'd', ]; // ::sort() also takes an optional custom comparison callable. $sort = iter($array)->sort(); $expected = [ 1 => 'a', 3 => 'c', 4 => 'd', ]; assert($expected === iterator_to_array($sort)); ?>
sortKeys
按键对项进行排序。
<?php $array = [ 'c' => 3, 'a' => 1, 'd' => 4, ]; // ::sortKeys() also takes an optional custom comparison callable. $sort = iter($array)->sortKeys(); $expected = [ 'a' => 1, 'c' => 3, 'd' => 4, ]; assert($expected === iterator_to_array($sort)); ?>
chain
将其他可迭代项链接到现有迭代器,并重新索引值。
<?php $arrayOne = [3, 1, 4]; $arrayTwo = [1, 5, 9]; $arrayThree = [2, 6, 5]; $iterator = iter($arrayOne)->chain($arrayTwo, $arrayThree); $expected = [3, 1, 4, 1, 5, 9, 2, 6, 5]; assert($expected === $iterator->toArray()); ?>
flatten
将迭代器中包含的可迭代对象展平到一个新的迭代器中。
<?php $array = [ [3, 1, 4], [1, 5, 9], [2, 6, 5], ]; $iterator = iter($array)->flatten(); $expected = [3, 1, 4, 1, 5, 9, 2, 6, 5]; assert($expected === $iterator->toArray()); ?>
unique
移除所有重复的值。
<?php $objectOne = new \stdClass(); $objectTwo = new \stdClass(); $array = [0, false, false, null, [], [], '0', $objectOne, $objectOne, $objectTwo]; $iterator = iter($array)->unique(); $expected = [ 0 => 0, 1 => false, 3 => null, 4 => [], 6 => '0', 7 => $objectOne, 9 => $objectTwo, ]; assert($expected === $iterator->toArray()); ?>
异常处理
复杂的try
/catch
块可以被替换并轻松转换为Result
。
<?php // Try executing a callable, catch all exceptions, and output a Result. $result = F\try_except(function () {/** ... */}); // Try executing a callable, catch all Foo, Bar, Baz, and Qux exceptions, and output a Result. $result = F\try_except(function () {/** ... */}, Foo::class, Bar::class, Baz::class, Qux::class); // Try executing a callable at most twice, catch all exceptions, and output a Result. $result = F\retry_except(function () {/** ... */}); // Try executing a callable at most 5 times, catch all Foo, Bar, Baz, and Qux exceptions, and output a Result. $result = F\retry_except(function () {/** ... */}, 5, Foo::class, Bar::class, Baz::class, Qux::class); ?>
谓词
谓词可以与filter()
和find()
一起使用。它们可以是任何接受单个参数并返回布尔值的可调用函数,但我们添加了一些用于常见条件的快捷方式。这些函数接受配置参数,并返回谓词。
<?php // All values strictly identical to TRUE. $predicate = P\true(); // All values strictly identical to FALSE. $predicate = P\false(); // All values that evaluate to TRUE. $predicate = P\truthy(); // All values that evaluate to FALSE. $predicate = P\falsy(); // All values strictly identical to 0. $predicate = P\id(0); // All values equal to "Apples and oranges". $predicate = P\eq('Apples and oranges'); // All values greater than 9. $predicate = P\gt(9); // All values greater than or equal to 99. $predicate = P\ge(99); // All values lesser than 15. $predicate = P\lt(15); // All values lesser than or equal to 666. $predicate = P\le(666); // All values that are instances of Foo, Bar, Baz, or Qux. $predicate = P\instance_of(Foo::class, Bar::class, Baz::class, Qux::class); // One or more values are lesser than 0 OR greater than 9. $predicate = P\any(P\lt(0), P\gt(9)); // All values are greater than 0 AND lesser than 9. $predicate = P\all(P\gt(0), P\lt(9)); // All values different from "Apples and oranges". $predicate = P\not(P\eq('Apples and oranges')); ?>
Option
类型
在PHP中,NULL
表示值的缺失,但它本身也被用作一个值。在这种情况下,Option
类型有助于区分作为值的NULL
和完全没有值的情况。
<?php use BartFeenstra\Functional\Option; use BartFeenstra\Functional\Some; use BartFeenstra\Functional\SomeValue; use BartFeenstra\Functional\None; function get_option(): Option { if (true) { return new SomeValue(666); } return new None(); } function handle_option(Option $value) { if ($value instanceof Some) { print sprintf('The value is %s.', $value()); } // $value is an instance of None. else { print 'No value could be retrieved.'; } } handle_option(get_option()); ?>
Result
类型
Result
类型可用于补充或替换异常。因此,它由如try_except()
这样的函数返回。它表示成功和值,或错误。
<?php use BartFeenstra\Functional\Ok; use BartFeenstra\Functional\OkValue; use BartFeenstra\Functional\Result; use BartFeenstra\Functional\ThrowableError; function get_result(): Result { try { // Do some things that may throw a ResultComputationException. return new OkValue(666); } catch (\ResultComputationException $e) { return new ThrowableError($e); } } function handle_result(Result $result) { if ($result instanceof Ok) { print sprintf('The value is %s.', $result()); } // $value is an instance of Error. else { print sprintf('An error occurred: %s.', $result); } } handle_result(get_result()); ?>
部分函数应用
部分函数应用是基于现有函数创建一个新函数(带有零个或多个参数),通过在调用之前固定原始函数的一个或多个参数。实际上,这允许你复制一个函数,并在调用之前填充一些参数。你可以使用它来快速将现有函数转换为匿名函数,这些函数可以用作回调。在PHP中,这可以通过任何类型的可调用(函数、方法、闭包等)实现。
<?php $originalFunction = function (string $a, string $b, string $c, string $d): string { return $a . $b . $c . $d; }; // Fix the two first/left-handed arguments. $newFunction = F\apply_l($originalFunction, 'A', 'B'); assert('ABCD' === $newFunction('C', 'D')); // Fix the two last/right-handed arguments. $newFunction = F\apply_r($originalFunction, 'C', 'D'); assert('ABCD' === $newFunction('A', 'B')); // Fix two arguments by index/in the middle. $newFunction = F\apply_i($originalFunction, 1, 'B', 'C'); assert('ABCD' === $newFunction('A', 'D')); ?>
柯里化
柯里化将具有n个参数的单个函数转换为具有单个参数的n个函数。实际上,这允许你复制一个函数,并在调用之前逐个填充一些参数。你可以使用它来快速将现有函数转换为匿名函数,这些函数可以用作回调。在PHP中,这可以通过任何类型的可调用(函数、方法、闭包等)实现。
<?php $originalFunction = function (string $a, string $b, string $c, string $d = 'D'): string { return $a . $b . $c . $d; }; assert('ABCD' === F\curry($originalFunction)('A')('B')('C')); ?>
贡献
欢迎您的参与。请在问题中留下反馈,或通过拉取请求提交代码改进。
互联网和这个项目是一个属于所有人的地方。我们将保持其友好和高效,如我们的行为准则中所述,其中还包含了项目维护者的联系方式,以便您在需要的情况下报告情况,代表自己或他人。
开发
构建代码
运行./bin/build
。
测试代码
运行./bin/test
。
修复代码
运行./bin/fix
来自动修复可修复的部分。
代码风格
所有PHP代码遵循PSR-2。