PHPackages                             timfennis/apply - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. timfennis/apply

ActiveLibrary

timfennis/apply
===============

Functional programming library

0.4.0(5y ago)3320[1 PRs](https://github.com/timfennis/apply/pulls)Apache-2.0 AND MITPHPPHP &gt;=8.0

Since Jun 14Pushed 3y ago2 watchersCompare

[ Source](https://github.com/timfennis/apply)[ Packagist](https://packagist.org/packages/timfennis/apply)[ RSS](/packages/timfennis-apply/feed)WikiDiscussions master Synced 2mo ago

READMEChangelogDependencies (6)Versions (22)Used By (0)

Apply
=====

[](#apply)

[![codecov](https://camo.githubusercontent.com/b1a65af802c5548f8078d04d8ce72a93f7ee90292a54b51d2d4ea441b73c9e98/68747470733a2f2f636f6465636f762e696f2f67682f74696d66656e6e69732f6170706c792f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/timfennis/apply)[![Build Status](https://camo.githubusercontent.com/6b83fc9dfd98bd69a79d1af6ef48b455d28159a2c0216f736d72fc0f38629d69/68747470733a2f2f64726f6e652e74696d66656e6e69732e636f6d2f6170692f6261646765732f74696d66656e6e69732f6170706c792f7374617475732e737667)](https://drone.timfennis.com/timfennis/apply)

Apply is a **PHP Library** that aims to promote and bring functional programming ideas from different languages and libraries such as Haskell, Scala, Kotlin, Arrow and Cats to PHP.

Stability
---------

[](#stability)

The library is currently very much a work in progress. Everything could change at any moment.

Contributing
------------

[](#contributing)

I'm currently looking for ideas, suggestions, criticisms and contributions. The library is very much in a draft state, some functions probably don't work they way they 'should' and test coverage is still only 50ish percent.

- If you have any ideas for functional programming concepts that could work well in PHP, please open an issue or PR and get involved.
- If you see any functions that don't work the way they should, or could be improved performance wise feel free to open a PR or issue and let me now!
- If you have any ideas, long term visions, or do you just think this whole library is stupid? Feel free to open an issue and let me know!

Curried Functions
-----------------

[](#curried-functions)

### Collections

[](#collections)

All collection functions in this library attempt to follow a pattern in terms of naming and argument order. Usually the names and arguments you'll find are taken from Haskell's standard library. Every function has a Curried version where the argument order matches the one in Haskell. In this argument order the subject of the function is always the last argument so that the curried functions can be used to create partially applied functions that can be chained together in different ways. All of these functions also have imperative counterparts that are easier to use and read in some situations. These functions have the same argument order except that the subject is now the first argument followed by the other arguments in the same order. This order is chosen because it's easier to read in imperative code and because it's similar to most other languages.

Functions that return collections of elements will always return Generators in order to be as lazy as possible. Functions that return a single element, or a scalar value are not lazy.

#### All

[](#all)

```
$list = [5, 6, 7, 8, 9, 10];

$gt4 = fn($n) => $n > 4;
$gt5 = fn($n) => $n > 5;

all($gt4)($list); // true because all items are greater than 4
all($gt5)($list); // false because not all items are greater than 5
```

#### Any

[](#any)

Returns true if any (or some) of the predicates are true.

```
$list = [5, 6, 7, 8, 9, 10];

$gt7 = fn($n) => $n > 7;
$gt20 = fn($n) => $n > 20;

any($gt7)($list); // true because all items are greater than 7
any($gt20)($list); // false because none of the items are greater than 20
```

### `identity` and `constant`

[](#identity-and-constant)

These two guys can often be very useful in many situations. `constant` returns a function that always returns the value that you passed to it. While identity is a function that always returns it's argument.

```
$numbers = [1,2,3];
map(Functions::identity)($numbers); // [1,2,3]
map(constant(4))($numbers); // [4,4,4]
```

Monads
------

[](#monads)

Check [this](https://arrow-kt.io/docs/patterns/monads/) page for a good tutorial on what Monads are. You don't really have to understand them in order to (ab)use them though.

### Try

[](#try)

`Attempt` represents the result of a computation that can either have a result when the computation was successful, or an exception if something went wrong. If the computation went correctly you get a `Success` containing the result and if the computation goes wrong you get a `Failure` containing the exception.

`Attempt` looks a lot like `Either` but is especially useful in situations where you have to consume some library or language feature that throws unwanted exception. `Attempt` can be used to capture exceptions and performing computations on the result without having to build complicated and verbose `try-catch` blocks.

```
function loadFromAPI() {
    throw new InvalidAuthenticationCredentialsException('Your authentication credentials are invalid');
}

$tryLoad = Attempt::of(fn() => loadFromAPI());
$result = $tryLoad->getOrDefault(null); // returns null

if ($tryLoad->isFailure()) {
    // true it went wrong!
}
```

Most often you may want to fold over the computation

```
$tryLoad = Attempt::of(fn() => rollTheDice());

$number = $tryLoad->fold(
    fn(Throwable $t) => 0,
    fn(int $successValue) => $successValue + 1
);
```

### Option (Maybe)

[](#option-maybe)

The Option monad is a modern rewrite of `schmittjoh/php-option` which can be found [here](https://github.com/schmittjoh/php-option). It's designed to be mostly compatible with its interface.

Suggestions are welcome.

### Either

[](#either)

```
/**
 * @return Either
 */
function loadFromApi(): Either {
    try {
        return new Right(httpGet("http://example.com"));
    } catch (RequestException $e) {
        return new Left("Request Error");
    } catch (ResponseException $e) {
        return new Left("Response Error");
    }
}
```

Instead of using `string` as type directly you probably want to define your own error types like `RequestError` and `ResponseError`. Those types could then have meaningful properties that assist with error handling.

### EvalM

[](#evalm)

Wrapper around a lazy computation.

Monad Comprehensions
--------------------

[](#monad-comprehensions)

Many programming languages have a form of monad comprehensions, but they go by different names with slightly different implementations. In Haskell, you have the 'do notation', in Scala you have for-comprehensions and in JavaScript you can use async/await to accomplish similar results.

In PHP, we don't have much use for asynchronous programming and IO monads, but the syntax of monad comprehensions can still offer us a way to combine the results of many monads elegantly.

First let's look at one example that doesn't look very nice. Here we have two computations that can fail in some way. In order to combine the results of these computations whe have to take them out of the 'package' that they came in, combine the results and wrap them back up. Your code may look something like this.

```
$computeA = fn() => Option::fromValue(1);
$computeB = fn() => Option::fromValue(5);

$sum = $computeA()->flatMap(static function ($a) use ($computeB) {
    return $computeB()->flatMap(static function ($b) use ($a) {
        return new Some($a + $b);
    });
});

$sum; // Some(6)
```

Now this is already pretty terrible but imagine you want to combine the result of 3 or even 10 options, welcome in callback hell.

The solution:

```
$computeA = fn() => Option::fromValue(1);
$computeB = fn() => Option::fromValue(5);

$sum = Option::binding(static function () use ($computeA, $computeB) {
    $a = yield $computeA();
    $b = yield $computeB();
    return $a + $b;
});

$sum; // Some(6)
```

That looks a lot more like the kind of code that you want to write! It's not perfect because we have to wrap the whole thing in a callable and pass that to the `binding` function, but it's much easier to read then our first example. Especially if the amount of computations increases.

License
-------

[](#license)

Most of the source code in this project is licensed under MIT. The `Apply\Option` packages is derived from `schmittjoh/php-option` which is licensed under Apache-2.0.

`SPDX-License-Identifier: Apache-2.0 AND MIT`

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 98.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~33 days

Recently: every ~70 days

Total

20

Last Release

1902d ago

PHP version history (3 changes)v0.0.1PHP &gt;=7.3

v0.3.0PHP &gt;=7.4

0.4.0PHP &gt;=8.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/c44db2d991981d2922410420589e8a70b430e99071e0add4aa5ee8d48c500ade?d=identicon)[timfennis](/maintainers/timfennis)

---

Top Contributors

[![timfennis](https://avatars.githubusercontent.com/u/1632739?v=4)](https://github.com/timfennis "timfennis (86 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

arrowfunctional-programmingmonadphpphp-libraryphp74phpfunctional-programmingfp

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/timfennis-apply/health.svg)

```
[![Health](https://phpackages.com/badges/timfennis-apply/health.svg)](https://phpackages.com/packages/timfennis-apply)
```

###  Alternatives

[mpetrovich/dash

A functional programming library for PHP. Inspired by Underscore, Lodash, and Ramda.

10428.9k1](/packages/mpetrovich-dash)[pestphp/pest-plugin-stressless

Stressless plugin for Pest

67792.6k16](/packages/pestphp-pest-plugin-stressless)[chemem/bingo-functional

A simple functional programming library.

716.9k3](/packages/chemem-bingo-functional)[boehm_s/fun

Functional programming utilities for PHP

301.8k](/packages/boehm-s-fun)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
