WIP on pipeable array functions

This commit is contained in:
2026-01-25 22:54:25 -05:00
parent c61ff7a831
commit 34db7b1295
5 changed files with 1007 additions and 634 deletions

View File

@@ -2,11 +2,15 @@
This project contains PHP utility classes whose functionality is inspired by their F# counterparts.
The v2 series requires at least PHP 8.4. A similar API exists for PHP 8.2 - 8.3 in version 1 of this project; see its README for specifics.
The v3 series requires at least PHP 8.5, and includes pipeable `array_*` functions. The v2 series requires at least PHP 8.4. A similar v2 API exists for PHP 8.2 - 8.3 in version 1 of this project; see its README for specifics.
## What It Provides
This early-stage library currently provides two classes, both of which are designed to wrap values and indicate the state of the action that produced them. `Option<T>` represents a variable that may or may not have a value. `Result<TOK, TError>` represents the result of an action; the "ok" and "error" states both provide a value.
This library currently provides three classes.
### `Option`s and `Result`s
Two of them are designed to wrap values and indicate the state of the action that produced them. `Option<T>` represents a variable that may or may not have a value. `Result<TOK, TError>` represents the result of an action; the "ok" and "error" states both provide a value.
| | `Option<T>`<br>Replaces `null` checks | `Result<TOK, TError>`<br>Replaces exception-based error handling |
|---------------------------------------------------|-------------------------------------------------------|-----------------------------------------------------------------------------|
@@ -34,7 +38,38 @@ In addition to this, `Option<T>` provides:
- `->filter(callable(T): bool)` will compare a Some value against the callable, and if it returns `true`, will remain Some; if it returns `false`, the value will become None.
- `->unwrap()` will return `null` for None options and the value for Some options.
Finally, we would be remiss to not acknowledge some really cool prior art in this area - the [PhpOption](https://github.com/schmittjoh/php-option) project. `Option::of` recognizes their options and converts them properly, and `Option<T>` instances have a `->toPhpOption()` method that will convert these back into PhpOption's `Some<T>` and `None` instances. There is also a [ResultType](https://github.com/GrahamCampbell/Result-Type) project from the same team, though this project's result does not (yet) have any conversion methods for it.
> We would be remiss to not acknowledge some excellent prior art in this area - the [PhpOption](https://github.com/schmittjoh/php-option) project. `Option::of` recognizes their options and converts them properly, and `Option<T>` instances have a `->toPhpOption()` method that will convert these back into PhpOption's `Some<T>` and `None` instances. There is also a [ResultType](https://github.com/GrahamCampbell/Result-Type) project from the same team, though this project's result does not (yet) have any conversion methods for it.
### Pipeable `array_*` Functions
The final class, exclusive to v3, is `Arr`, which wraps the `array_*` functions with versions that return a single-arity (AKA "one parameter") function which takes the array and returns the result.
The `array_map` example is easy to understand. This function requires the array first, and the transformation callback second. This does not play nicely with PHP 8.5's pipeline operator (`|>`); to pipe to `array_map`, one has to create an anonymous function to reverse the parameters. `Arr::map()` does this for you.
```php
// The result of both calls is [2, 4, 6]
// Without this library
$withoutLibrary =
[1, 2, 3]
|> fn ($arr) => array_map($arr, fn ($x) => x * 2);
// With this library
$withLibrary =
[1, 2, 3]
|> Arr::map(fn ($x) => $x * 2);
```
All `array_*` functions which expect the target array as the first parameter have a matching `Arr::*` function which provides a version of the function with the array last. `array_*` functions which only take the array (such as `array_count_values` or `array_keys`) have corresponding functions in `Arr` for completeness; when piping to these, call the `Arr` function vs. using it as a `callable`.
```php
// Use this
$theKeys = $array |> Arr::keys();
// ...or this
$theKeys = $array |> array_keys(...);
// Not this
$theKeys = $array |> Arr::keys(...);
```
## The Inspiration
@@ -65,7 +100,7 @@ $value = Option::of($myVar)
->getOrDefault('There was no string');
```
If PHP gets a pipeline operator, we'll revisit lots of stuff here (in a non-breaking way, of course).
If PHP gets a pipeline operator (TODO: !!!!), we'll revisit lots of stuff here (in a non-breaking way, of course).
## Ideas