定制 denprog/river-flow 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

denprog/river-flow

最新稳定版本:v0.3.0

Composer 安装命令:

composer require denprog/river-flow

包简介

Functional utilities for PHP 8.5: lazy Pipes, mbstring-aware Strings, and composition Utils with pipe operator support.

README 文档

README

CI License: MIT PHP

Modern, strictly-typed functional utilities for PHP 8.5: lazy collection pipelines (Pipes), mbstring‑aware string helpers (Strings), and ergonomic composition tools (Utils). Designed for the PHP 8.5 pipe operator |> and built with rigorous QA (Pest, PHPStan max, Rector, CS).

Highlights

  • Pipe operator first: idiomatic |> pipelines, no external wrappers
  • Lazy + eager: predictable key behavior, memory‑friendly where it matters
  • Strong typing: precise PHPDoc generics, PHPStan at max level
  • Unicode aware: Strings use mbstring when available
  • Ergonomics: tap, identity, compose, pipe
  • Cross‑platform CI: Linux/macOS/Windows

Requirements

  • PHP >= 8.5
  • Composer 2

Install

composer require denprog/river-flow

Quickstart

<?php

declare(strict_types=1);

use function Denprog\RiverFlow\Pipes\{map, filter, toList};
use function Denprog\RiverFlow\Strings\{trim, toUpperCase};

$result = [10, 15, 20, 25, 30]
    |> filter(fn (int $n) => $n % 2 === 0) // [10, 20, 30]
    |> map(fn (int $n) => $n / 10)         // [1, 2, 3]
    |> toList();                           // [1, 2, 3]

$text = "  river flow  "
    |> trim()
    |> toUpperCase(); // "RIVER FLOW"

Dual‑mode usage (direct and pipe‑friendly)

  • Direct: pass data as the first argument, e.g. toList([1,2,3])
  • Curried / pipe‑friendly: call a function without the data argument to get a callable, then chain with |>
use function Denprog\RiverFlow\Pipes\{map, filter, toList};

$res1 = toList(map(filter([1,2,3,4], fn($x)=>$x%2===0), fn($x)=>$x*10))); // [20, 40]

$res2 = [1,2,3,4]
    |> filter(fn($x) => $x % 2 === 0)
    |> map(fn($x) => $x * 10)
    |> toList(); // [20, 40]

Other composition helpers (non‑pipe)

In addition to the |> operator, RiverFlow provides classic composition utilities in Utils which do not require pipes.

use function Denprog\RiverFlow\Utils\{compose, pipe};

$sum = fn (int $a, int $b): int => $a + $b;   // right‑most may be variadic
$inc = fn (int $x): int => $x + 1;
$dbl = fn (int $x): int => $x * 2;

$f = compose($dbl, $inc, $sum); // dbl(inc(sum(a,b)))
assert($f(3, 4) === 16);

$out = pipe(5, fn($x) => $x + 3, fn($x) => $x * 2, 'strval');
assert($out === '16');

Module snapshots

Pipes

use function Denprog\RiverFlow\Pipes\{filter, map, take, toList, toArray, flatten, uniq, groupBy, values, sortBy, zipWith, range, repeat, times, tail, init, scan, scanRight, partitionBy, distinctUntilChanged, intersperse, pairwise, countBy};

// Transform → filter → take → materialize
$topSquares = [1,2,3,4,5,6,7,8,9]
    |> map(fn (int $n) => $n * $n)
    |> filter(fn (int $x) => $x % 2 === 0)
    |> take(3)
    |> toList(); // [4, 16, 36]

// Flatten nested, uniquify
$flatUnique = [[1,2], [2,3, [3,4]], 4]
    |> flatten(2)
    |> uniq()
    |> toList(); // [1,2,3,4]

// Group, traverse group values and sort by size
$byFirstLetter = ['apple','apricot','banana','blueberry','avocado']
    |> groupBy(fn (string $s) => $s[0])
    |> values()
    |> map(fn (array $xs) => $xs)
    |> toList()
    |> sortBy(fn (array $xs) => \count($xs));

// Zip in pipelines
$zipped = [1, 2, 3]
    |> zipWith(['a','b'], ['X','Y','Z'])
    |> toList(); // [[1,'a','X'], [2,'b','Y']]

// Numeric ranges and generation
$nums = range(0, 5) |> toList(); // [0,1,2,3,4]

// Infinite repetition capped with take
$threes = repeat(3) |> take(4) |> toList(); // [3,3,3,3]

// Produce values by index
$squares = times(5, fn (int $i): int => $i * $i) |> toList(); // [0,1,4,9,16]

$rest = ['a'=>1,'b'=>2,'c'=>3]
    |> tail()
    |> toArray(); // ['b'=>2,'c'=>3]

$allButLast = ['x'=>10,'y'=>20,'z'=>30]
    |> init()
    |> toArray(); // ['x'=>10,'y'=>20]

// Inclusive prefix and suffix scans (lazy, keys preserved)
$prefix = [1, 2, 3, 4]
    |> scan(fn (?int $c, int $v) => ($c ?? 0) + $v, 0)
    |> toList(); // [1, 3, 6, 10]

$suffix = [1, 2, 3]
    |> scanRight(fn (?int $c, int $v) => ($c ?? 0) + $v, 0)
    |> toList(); // [6, 5, 3]

// Partition into contiguous groups by discriminator (lazy)
$groups = ['ant', 'apple', 'bear', 'bob', 'cat']
    |> partitionBy(fn (string $s) => $s[0])
    |> toList();
// [[0=>'ant',1=>'apple'], [2=>'bear',3=>'bob'], [4=>'cat']]

// Skip consecutive duplicates (preserves first keys of runs)
$d = ['ant', 'apple', 'bear', 'bob', 'cat']
    |> distinctUntilChanged(fn (string $s) => $s[0])
    |> toArray(); // [0=>'ant', 2=>'bear', 4=>'cat']

// Intersperse a separator (keys discarded)
$withPipes = ['a','b','c']
    |> intersperse('|')
    |> toList(); // ['a','|','b','|','c']

// Pairwise (consecutive pairs)
$pairs = [1,2,3]
    |> pairwise()
    |> toList(); // [[1,2],[2,3]]

// Count by classifier (eager)
$counts = ['apple','apricot','banana','blueberry','avocado']
    |> countBy(fn (string $s) => $s[0]); // ['a' => 3, 'b' => 2]

Strings

use function Denprog\RiverFlow\Strings\{trim, replacePrefix, toLowerCase, toUpperCase, split, join, length};

$title = "  River FLOW: Intro  "
    |> trim()
    |> toLowerCase()
    |> replacePrefix('river ', 'river ');
// "river flow: intro"

$csv = ' foo | Bar |BAZ '
    |> trim()
    |> toLowerCase()
    |> split('|')
    |> join(','); // "foo , bar ,baz"

$n = '  Hello  ' |> trim() |> toUpperCase() |> length(); // 5

Utils

use function Denprog\RiverFlow\Utils\{tap, identity};
use function Denprog\RiverFlow\Strings\{trim, toUpperCase};

$result = '  Hello  '
    |> trim()
    |> tap(fn (string $s) => error_log("after trim: $s"))
    |> toUpperCase()
    |> tap(fn (string $s) => error_log("after upper: $s"));
// 'HELLO'

$val = 10
    |> identity()
    |> (fn (int $x) => $x + 5)
    |> (fn (int $x) => $x * 2); // 30

Documentation

Development

composer install

# QA
composer test            # Pest
composer analyse         # PHPStan (max)
composer cs:lint         # PHP-CS-Fixer (dry-run)
composer rector:check    # Rector (dry-run)
composer cs:fix          # Apply PHP-CS-Fixer fixes
composer rector:fix      # Apply Rector refactors

Security

See SECURITY.md for our vulnerability disclosure policy.

Contributing

See CONTRIBUTING.md for setup, standards (PSR-12), and PR process.

Code of Conduct

This project adheres to the Contributor Covenant. See CODE_OF_CONDUCT.md.

Versioning & Changelog

We follow SemVer. See CHANGELOG.md for release notes.

License

MIT — see LICENSE.

统计信息

  • 总下载量: 2
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 0
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-08-15