atomicptr/functional

A set of tools to enable a more functional style of programming in PHP, inspired by OCaml

v0.7.0 2024-08-12 13:36 UTC

This package is auto-updated.

Last update: 2024-08-12 13:37:45 UTC


README

A set of tools to enable a more functional style of programming in PHP, inspired by OCaml.

<?php

// lots of list utility functions
list($even, $odd) = Lst::partition(fn (int $num) => $num % 2 === 0, [1, 2, 3, 4, 5, 6]);
//     $even is [2, 4, 6]
//     $odd is  [1, 3, 5]

// pipe a bunch of operations
Collection::from(Lst::init(fn (int $index) => $index * $index, 100))
    ->filter(fn (int $num) => $num % 2 === 0)
    ->filter(fn (int $num) => $num > 50)
    ->map(fn (int $num, int $index) => $num * $index)
    ->foldl(fn (int $acc, int $val) => $acc + $val, 0);

// better error handling with Result
function safeDivision(int $a, int $b): Result
{
    if ($b === 0) {
        return Result::error("cant divide by 0");
    }

    return Result::ok($a / $b);
}

$res = safeDivision(10, 2);

if ($res->hasError()) {
    print($res->value());
    exit(1);
}

// use bind for Result or Option to only continue as long as there is a value
// lets assume we have a function fetch(string $url): Result that just returns
// the response as a string wrapped into Result
$title = fetch("https://atomicptr.dev/api/blog/post/1337")
    ->bind(fn (string $response) => Result::capture(fn () => json_decode($resp, true, flags: JSON_THROW_ON_ERROR)))
    ->bind(function (array $data) {
        assert(BlogPostSchema::isValid($data)); // A ficticious json schema validator
        return BlogPostResource::createFrom($data); // This converts the json data into a structure
    })->bind(fn (BlogPost $post) => $post->title());

if ($title->hasError()) {
    // something went wrong along the chain, so just panic
    $title->panic();
    exit(1);
}

// express "nothing" without using null
function findOneById(int $id): Option
{
    $rows = DB::find("table_name", ["id" => $id]);

    if (empty($rows)) {
        return Option::none();
    }

    return Option::some($rows[0]);
}

$row = findOneById(1337);

if ($row->isNone()) {
    print("Can not find object 1337");
    exit(1);
}

// ...

Install

The package is available on packagist

Install via:

$ composer req atomicptr/functional

Docs

Atomicptr\Functional

License

MIT