slava-basko/functional-php

该包最新版本(dev-main)没有提供许可证信息。

一组PHP函数,允许您以声明方式编写代码。

dev-main 2024-09-13 01:41 UTC

This package is auto-updated.

Last update: 2024-09-13 20:44:25 UTC


README

一组PHP函数,允许您以声明方式编写代码。

通用 ⚙️

命名约定

使用 snake_case 以更接近PHP原生函数。

无依赖

此库不依赖于任何外部库。

PHP 5.5+

支持PHP版本从5.5开始。为什么?因为遗留项目也值得采用一些函数式方法。

"数据最后"原则

要操作的数据通常在最后提供(最后函数参数)。这种方式使得函数更便于柯里化。

函数默认柯里化

这允许我们通过不提供最终参数,更高效地从旧函数中构建新函数。

最后两点结合使得构建函数序列变得容易,每个函数都转换数据并将其传递给下一个。

文档 📚

在这里您可以找到可用的函数。

函数列表

其他有用的东西。

OOP 🤝 FP

此库的目的不是取代命令式和OOP。它们可以结合使用,我相信它们应该结合使用,因为任何一种方法都不是万能的。

我将省略关于函数式编程的理论,因为您自己可以找到很多关于它的信息。但我想给您展示一些示例。

集合示例

让我们假设您正在使用集合库,并且想要将所有元素转换为大写。您需要编写如下内容

$collection = new Collection(['one']);
$collection->map(function ($value) {
    return strtoupper($value);
});

当您编写 $collection->map('strtoupper'); 时,您可能会得到一个错误,例如 ArgumentCountError : strtoupper() expects exactly 1 argument, X given。只有用户定义的函数在调用时带有更多参数时不会抛出异常。但您可以这样做

$collection = new Collection(['one']);
$collection->map(unary('strtoupper'));

bam! 您得到了更简洁的代码,没有 function{return};。函数 unary 是一个高阶函数,它接受任意数量的函数并返回只接受一个参数的新函数。

这就是我所说的将命令式/OOP和函数式代码结合起来的意思。

集合的另一个示例。我们需要通过 isActive 方法过滤用户,例如。

$collection = new Collection([$user1, $user2, $user3]);

$collection->filter(function ($user) {
    return $user->isActive();
});

// VS

$collection->filter(invoker('isActive'));

无参数示例

现在让我们考虑第二个示例,当我们需要按顺序计算商品数量时。

$products = [
    [
        'description' => 't-shirt',
        'qty' => 2,
        'value' => 20
    ],
    [
        'description' => 'jeans ',
        'qty' => 1,
        'value' => 30
    ],
    [
        'description' => ' boots',
        'qty' => 1,
        'value' => 40
    ],
];

$imperativeTotalQty = 0;
foreach ($products as $product) {
    $imperativeTotalQty += $product['qty'];
}

// OR
$totalQty = compose(sum, pluck('qty'))($products);

您可以将代码 compose(sum, pluck('qty')) 读取为 'quantity' 属性的总和。好吧,我理解这可能对您来说有点奇怪。您习惯了以不同的方式编写代码。

管道和部分应用

我们有一个 $products[],我们需要从每个商品的 description 属性中创建一个通用描述。所以,这里有一些基本步骤

  1. 从产品中获取属性 'description'。
  2. 去除每个值的首尾空白字符。
  3. 删除空元素。
  4. 用逗号连接元素。
  5. 将生成的描述截断到34个字符。
  6. 如果存在,删除结尾的逗号。

命令式的方法可能是

$commonDescription = trim(substr(implode(', ', array_filter(array_map('trim', array_column($products, 'description')), 'strlen')), 0, 34), ', ');
// OR
$commonDescription = trim(
    substr(
        implode(
            ', ', 
            array_filter(
                array_map(
                    'trim', 
                    array_column($products, 'description')
                ), 
                'strlen'
            )
        )
        , 0, 34
    ),
    ', '
);

认知负荷相当大 🤯。让我们重新排序并使其更易于阅读。

$descriptions = array_column($products, 'description');
$trimmedDescriptions = array_map('trim', $descriptions);
$nonEmptyDescriptions = array_filter($trimmedDescriptions, 'strlen');
$descriptionString = implode(', ', $nonEmptyDescriptions);
$shortDescription = substr($descriptionString, 0, 34);
$commonDescription = trim($shortDescription, ', ');

现在它更容易阅读了,但我们需要处理状态。

函数式代码可能如下所示

$commonDescription = pipe(
    pluck('description'),
    map(unary('trim')),
    select(unary('strlen')),
    join(', '),
    take(34),
    partial_r('trim', ', ')
)($products);

这正是我们需要的。它按自然顺序排列。没有中间状态。

另一个例子,其中我们需要获取用户的首字母。

$initials = pipe(
    partial('explode', ' '),
    map(pipe(take(1), partial_r(concat, '.'))),
    join(' ')
)('Slava Basko');

// $initials = 'S. B.'

我知道,也许那一行看起来有点奇怪,但无需在每个步骤停下来考虑控制流结构和参数命名,就可以组合函数的想法非常强大。

有什么现实生活中的例子吗? 🤔

没问题,这个项目有一个自动生成文档的脚本。完全以纯函数式的方式编写。

展示你的 doc_generator.php

在脚本开发过程中没有损坏任何变量。

许可证 ⚖️

随意使用。我没有任何责任或保证。可以视为MIT。