haspadar/primus
最新稳定版本:v0.9.0
Composer 安装命令:
composer require haspadar/primus
包简介
Primitive wrappers for PHP: strong typing for strings, ints, arrays, and more
README 文档
README
Object‑Oriented PHP Primitives
Primus is a library of object‑oriented PHP primitives. It provides common operations as small composable objects instead of functions.
Procedural PHP buries the steps inside out — you read from the innermost call:
strtolower(trim(substr($s, 0, 5)));
Primus reads top to bottom — each step is a named object:
(new Lowered( new Trimmed( new Sub(new TextOf($s), 0, 5), ), ))->value();
The pipeline is a value itself: store it, pass it around, decorate it further.
Reading the result is always explicit — call value().
Why?
-
nulleverywhere.
PHP's standard library leaksnullthrougharray_search,preg_match,mb_strposeven if you ban it in your project. Primus values are nevernull— missing input fails fast. -
Bare
arrayshapes.
Procedural functions takearray/stringand you re‑describe their shape with PHPDoc at every call site. In Primus the type lives in the class — each operation has a narrow constructor signature you write once. -
Closures hard to substitute.
Acallableis convenient until you need to swap it in a test, log every call, or wrap it in retry logic. AFunc/Predicate/BiFuncobject composes like any other class. -
Controlled flow.
Procedural chains run as you write them. A Primus pipeline runs only whenvalue()is called — building, passing and composing it costs nothing until you ask for the result.
Installation
composer require haspadar/primus
Text
To trim and lowercase:
$text = (new Lowered(new Trimmed(new TextOf(' Hello '))))->value(); // "hello"
To take a substring:
$text = (new Sub(new TextOf('Hello, world!'), 0, 5))->value(); // "Hello"
Lists
To filter and sort:
$big = (new Sorted( new Filtered( new ListOf(3, 1, 4, 1, 5, 9, 2, 6), new PredicateOf(static fn (int $x): bool => $x > 2), ), ))->value(); // [3, 4, 5, 6, 9]
To pluck a column from a list of rows:
$names = (new Plucked( new ListOf( ['id' => 1, 'name' => 'Alice'], ['id' => 2, 'name' => 'Bob'], ), 'name', ))->value(); // ['Alice', 'Bob']
Maps
To merge two maps with last‑wins precedence:
$merged = (new Merged( new MapOf(['a' => 1, 'b' => 2]), new MapOf(['b' => 99, 'c' => 3]), ))->value(); // ['a' => 1, 'b' => 99, 'c' => 3]
To index a list of rows by one column, with values from another:
$byId = (new PluckedBy( new ListOf( ['id' => 1, 'name' => 'Alice'], ['id' => 2, 'name' => 'Bob'], ), 'id', 'name', ))->value(); // [1 => 'Alice', 2 => 'Bob']
Scalars
To compose lazy boolean logic:
$between = (new And_( new GreaterThan(new Constant(5), new Constant(0)), new LessThan(new Constant(5), new Constant(10)), ))->value(); // true
To memoize an expensive computation:
$cached = new Sticky( new ScalarOf(static fn () => expensive_computation()), ); $cached->value(); // expensive_computation() runs once $cached->value(); // cached
Functions
To wrap a callable as a reusable, swappable object:
$double = new FuncOf(static fn (int $x): int => $x * 2); $double->apply(21); // 42
To memoize a function by its input:
$cached = new StickyFunc( new FuncOf(static fn (int $id): User => $repo->find($id)), ); $cached->apply(1); // hits the repo $cached->apply(1); // cached
To fall back to another function on failure:
$safe = new FuncWithFallback( new FuncOf(static fn (string $url): string => http_get($url)), new FuncOf(static fn (string $url): string => ''), );
Design rules
- No
null, nostaticmethods or properties, noisset()/empty() - All state
readonly, all classesfinal - One class = one behavior; composition over inheritance
- Computation is lazy until
value()
Enforced by haspadar/sheriff — a curated
bundle of PHPStan level 9, Psalm with custom EO rules, PHP‑CS‑Fixer, PHPMD,
PHPMetrics, Infection, and repository lints.
Inspired by Elegant Objects and cactoos.
Requirements
PHP 8.3+.
License
统计信息
- 总下载量: 3
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 4
- 点击次数: 3
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-10-10