Primitives for functional programming in PHP

Last update: May 18, 2022

Functional PHP: Functional primitives for PHP

Test

NOTE: functional-php used to come with a C extension that implemented most of the functions natively. As the performance differences weren’t that huge compared to the maintenance cost it has been removed.

A set of functional primitives for PHP, heavily inspired by Scala’s traversable collection, Dojo’s array functions and Underscore.js

  • Works with arrays and everything implementing interface Traversable
  • Consistent interface: for functions taking collections and callbacks, first parameter is always the collection, then the callback. Callbacks are always passed $value, $index, $collection. Strict comparison is the default but can be changed
  • Calls 5.3 closures as well as usual callbacks
  • All functions reside in namespace Functional to not raise conflicts with any other extension or library

Functional Comic

Installation

Run the following command in your project root:

composer require lstrojny/functional-php

Docs

Read the docs

Contributing

  1. Fork and git clone the project
  2. Install dependencies via composer install
  3. Run the tests via composer run tests
  4. Write code and create a PR

Mailing lists

Thank you

GitHub

https://github.com/lstrojny/functional-php
Comments
  • 1. Introduce autocurring and function composition

    What do you think about introducing to functional php autocurring and function composition?

    I have created working prototype of library with autocurring, function composition and making$collection as last argument: https://github.com/psliwa/rfp

    In my opinion it looks promising, allows to take advantage of functional programming in even better way. There is the chance to make new release, aka "functional php 2"?

    Reviewed by psliwa at 2014-09-07 13:54
  • 2. hashMap

    For my own use I wrote a function called hashMap to create associative arrays:

    >>> hashMap(
    ...     ['abc', 'foobar'],
    ...     function ($value) {
    ...         return [$value[0], $value];
    ...     }
    ... )
    => [
         "a" => "abc",
         "f" => "foobar",
       ]
    
    function hashMap($collection, callable $callback)
    {
        InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1);
    
        $aggregation = [];
    
        foreach ($collection as $index => $element) {
            list($key, $value) = $callback($element, $index, $collection);
            $aggregation[$key] = $value;
        }
    
        return $aggregation;
    }
    

    Is this something that would also be useful to others? If yes, I can prepare a proper pull request. Of course it can be named differently if there is a better term for what this function does.

    Reviewed by MazeChaZer at 2016-08-04 20:00
  • 3. Memoize as a high order function

    What do you think about transforming the memoize function into a high order function? I think it would become easier to use from the client perspective and it may simplify its internal implementation. I'm thinking of something like

    function memoize(callable $function, callable $hashGenerator = null) {
        if (null === $hashGenerator) {
            $hashGenerator = function(array $arguments) {
                // ...
            }
        }
    
        return function (...$arguments) use ($function, $hashGenerator) {
            static $localCache = [];
    
            $key = $hashGenerator($arguments);
    
            if (!array_key_exists($key, $localCache)) {
                $localCache[$key] = $callback(...$arguments);
            }
    
            return $localCache[$key];
        };
    }
    
    Reviewed by theUniC at 2015-06-26 14:13
  • 4. Add `ary` function which ignores arguments over the supplied number

    Added function which defines a function of an arbitry number of arguments and calls the provided callable with only the given number of arguments

    Didn't add tests as it wasn't obvious how they worked and wanted feedback before investing the time

    Reviewed by someonewithpc at 2020-03-28 20:08
  • 5. Add `entries` and `from_entries`, similar to JavaScript's `Object.entries` and `Object.fromEntries`

    Previous title: Add enumerate, similar to Python's

    This PR adds an enumerate(Transversable|array, int=) function that acts like Python's enumerate

    foreach (enumerate($this->hash) as $i => [$k => $v]) {
        // ...
    }
    

    My use case is to iterate over an array with string keys and have an associated integer that can be used as an ID

    Reviewed by someonewithpc at 2021-11-02 09:30
  • 6. Add tap()

    tap() calls the given $callback with the given $value, which, in quite a few cases, makes the code read more fluent and "functional":

    tap(User::create('John Doe'), function (User $user) {
        UserService::sendWelcomeEmail($user);
    })->login();
    
    // or
    
    tap(DisposableEmail::create('From Nigerian Prince with luv'), function (Email $email) {
        EmailManager::send($email);
    })->destroy();
    

    This function is inspired by Laravel, which is in turn inspired by Ruby.

    Reviewed by phanan at 2017-12-09 11:37
  • 7. [RFC] provide a `not` function

    Is it me or one currently can't invert a boolean-returning function ?

    I'd like a not function looking like:

    namespace Functional;
    
    function not(callable $callback) {
        return function($value) use ($callback) {
            return !$callback($value);
        };
    }
    

    see https://3v4l.org/G3vtd for a working impl.

    Do you think it's a good idea? If yes, I can try to make a PR.

    Thanks!

    Reviewed by docteurklein at 2016-08-11 08:43
  • 8. Multiple fn version of partition()

    Partition() currently only accepts one predicate function and splits an array in to two partitions, putting elements which pass in the first, and those which fail in the second.

    Partition() should accept n predicate functions, create n+1 partitions, and place each element in the partition of the first predicate it matches, with unmatched ones in the last.

    In the case of single predicate function the behavior should be unchanged.

    Reviewed by mkrauss at 2016-05-16 00:18
  • 9. Semigroup, Monoid, Functor, Monad and basic Option implementation

    I've added a few functional typeclasses using interfaces.

    Also, this PR provides a basic implementation of Scala Option (or Haskell Maybe). Option implements all included interfaces and comes with unit tests.

    Reviewed by ornicar at 2012-02-06 23:38
  • 10. Implement sort_by

    I implemented the function, but tests for it are failing, because for some reason PHPUnit thinks that the sort_by function is not defined. I don't know why that error occurs, as far as I can see the function is defined and used correctly. @lstrojny Can you help me with this one?

    Fixes #162

    Reviewed by gvlasov at 2018-07-04 09:30
  • 11. Flat map with key preservation

    I found myself in need of such a function

    So you could transform a list to a dictionary like so:

    $dictionary = flatMapWithKeys($list, function($element) {
        $key = ...
        $value = ...
        return [
            $key => $value,
        ];
    });
    

    Naive implementation would be something like this:

    function flatMapWithKeys(array $array, callable $fn)
    {
        $result = [];
        foreach ($array as $key => $value)
        {
            $result += $fn($value, $key);
        }
        return $result;
    }
    

    Would this be useful?

    Reviewed by Erikvv at 2016-11-09 14:22
  • 12. Use php-quickcheck for testing

    Generative testing looks ideal for Functional PHP and https://github.com/steos/php-quickcheck looks like a good implementation.

    TBD

    • [ ] weither to use it inside of PHPUnit or not. First instinct is rather not but the question is weither it's sensible to port tests like FunctionalTest and AnnotationsTest
    Reviewed by lstrojny at 2021-03-07 10:20
  • 13. Updating Pipe Tests for psalm branch

    Surprised to see InvalidArgumentException::assertCallback was removed with no apparent substitute on sight, implemented check for callables inside Pipe functor construction, and adding some docblocks that Psalm complained about.

    Reviewed by tzkmx at 2020-08-01 07:14
  • 14. Support psalm

    Add psalm annotations

    • [ ] Fix all issues found by psalm
    • [x] Increase type specificity
    • [x] Add @psalm-pure
    • [x] Add @psalm-assert
    • [ ] Add proper support for more complex cases like compose

    Type specificity

    • [x] Average
    • [x] ButLast
    • [x] Capture
    • [x] CompareObjectHashOn
    • [x] CompareOn
    • [x] Compose
    • [x] Concat
    • [x] ConstFunction
    • [x] Contains
    • [x] Converge
    • [ ] Curry
    • [ ] CurryN
    • [x] Difference
    • [x] DropFirst
    • [x] DropLast
    • [x] Each
    • [x] Equal
    • [x] ErrorToException
    • [x] Every
    • [x] Exceptions/InvalidArgumentException
    • [x] Exceptions/MatchException
    • [x] False
    • [x] Falsy
    • [x] Filter
    • [x] First
    • [x] FirstIndexOf
    • [x] FlatMap
    • [x] Flatten
    • [x] Flip
    • [x] Functional
    • [x] GreaterThan
    • [x] GreaterThanOrEqual
    • [x] Group
    • [x] Head
    • [x] Id
    • [x] Identical
    • [x] IfElse
    • [x] IndexesOf
    • [x] Intersperse
    • [x] Invoke
    • [x] InvokeFirst
    • [x] InvokeIf
    • [x] InvokeLast
    • [x] Invoker
    • [x] Last
    • [x] LastIndexOf
    • [x] LessThan
    • [x] LessThanOrEqual
    • [x] LexicographicCompare
    • [x] Map
    • [x] Match
    • [x] Maximum
    • [x] Memoize
    • [x] Minimum
    • [x] None
    • [x] Noop
    • [x] Not
    • [x] OmitKeys
    • [x] PartialAny
    • [x] PartialLeft
    • [x] PartialMethod
    • [x] PartialRight
    • [x] Partition
    • [x] Pick
    • [x] Pluck
    • [x] Poll
    • [x] Product
    • [x] Ratio
    • [x] ReduceLeft
    • [x] ReduceRight
    • [x] Reindex
    • [x] Reject
    • [x] Repeat
    • [x] Retry
    • [x] Select
    • [x] SelectKeys
    • [x] SequenceConstant
    • [x] SequenceExponential
    • [x] SequenceLinear
    • [x] Sequences/ExponentialSequence
    • [x] Sequences/LinearSequence
    • [x] Some
    • [x] Sort
    • [x] Sum
    • [x] SuppressError
    • [x] Tail
    • [x] TailRecursion
    • [x] TakeLeft
    • [x] TakeRight
    • [x] Tap
    • [x] True
    • [x] Truthy
    • [x] Unique
    • [ ] With
    • [ ] Zip
    • [ ] ZipAll

    Issues

    • invoker(), invoke(), partial_method(): no way to annotate method names properly: https://github.com/vimeo/psalm/issues/2500
    • Recursive types are not implemented (problem for compose, curry, etc.): https://github.com/vimeo/psalm/issues/2499
    Reviewed by lstrojny at 2019-12-19 16:06
sample code for several design patterns in PHP 8

DesignPatternsPHP Read the Docs of DesignPatternsPHP or Download as PDF/Epub This is a collection of known design patterns and some sample codes on ho

May 18, 2022
Option Type for PHP
Option Type for PHP

PHP Option Type This package implements the Option type for PHP! Motivation The Option type is intended for cases where you sometimes might return a v

May 11, 2022
A Simple PHP Finite State Machine

Finite, A Simple PHP Finite State Machine Finite is a Simple State Machine, written in PHP. It can manage any Stateful object by defining states and t

May 6, 2022
A simple stateless production rules engine for PHP 5.3+

Ruler Ruler is a simple stateless production rules engine for PHP 5.3+. Ruler has an easy, straightforward DSL ... provided by the RuleBuilder: $rb =

May 17, 2022
Powerful implementation of the Specification pattern in PHP

RulerZ The central idea of Specification is to separate the statement of how to match a candidate, from the candidate object that it is matched agains

May 13, 2022
A simple Monad library for PHP

MonadPHP This is a basic Monad library for PHP. Usage Values are "wrapped" in the monad via either the constructor: new MonadPHP\Identity($value) or t

Apr 18, 2022
YCOM Impersonate. Login as selected YCOM user 🧙‍♂️in frontend.

YCOM Impersonate Login as selected YCOM user in frontend. Features: Backend users with admin rights or YCOM[] rights, can be automatically logged in v

Jan 19, 2022
PHP Functional Programming library. Monads and common use functions.

Functional PHP PHP Functional Programming library. Monads and common use functions. Documentation Functions Monads Installation Composer $ composer re

May 17, 2022
A simple functional programming library for PHP
A simple functional programming library for PHP

bingo-functional A simple functional programming library for PHP. Requirement(s) PHP 7 or higher Rationale PHP, a language not commonly associated wit

May 18, 2022
Small library providing some functional programming tools for PHP, based on Rambda

Functional library for PHP. Features: set of useful functions helpful in functional programming all functions are automatically curried every array ca

Jan 31, 2022
Iteration primitives using generators

Iteration primitives using generators This library implements iteration primitives like map() and filter() using generators. To a large part this serv

May 3, 2022
Dictionary of attack patterns and primitives for black-box application fault injection and resource discovery.

FuzzDB was created to increase the likelihood of finding application security vulnerabilities through dynamic application security testing. It's the f

May 20, 2022
A complete and fully-functional implementation of the Jade template language for PHP

Tale Jade for PHP Finally a fully-functional, complete and clean port of the Jade language to PHP — Abraham Lincoln The Tale Jade Template Engine brin

May 4, 2021
A functional and simple rate limit control to prevent request attacks ready-to-use for PHP.

RateLimitControl A functional and simple rate limit control to prevent request attacks ready-to-use for PHP. Features: Prepared statements (using PDO)

Mar 13, 2022
PHP libraries that makes Selenium WebDriver + PHPUnit functional testing easy and robust
PHP libraries that makes Selenium WebDriver + PHPUnit functional testing easy and robust

Steward: easy and robust testing with Selenium WebDriver + PHPUnit Steward is a set of libraries made to simplify writing and running robust functiona

Apr 29, 2022
A functional Prison Management Portal completely developed on php

A functional Prison Management Portal completely developed on php, Inspired by existing models. With interactive modules, and high scalability because of MySQL.

Feb 7, 2022
Simple library that abstracts different metrics collectors. I find this necessary to have a consistent and simple metrics (functional) API that doesn't cause vendor lock-in.

Metrics Simple library that abstracts different metrics collectors. I find this necessary to have a consistent and simple metrics API that doesn't cau

Apr 27, 2022
Workout application with fully functional Frontend and Backend.
Workout application with fully functional Frontend and Backend.

Fit_Me_Application About Application: This FIT-ME management system is an easy way to use gym and health membership system. It can help to keep the re

Feb 20, 2022
A collection of type-safe functional data structures

lamphpda A collection of type-safe functional data structures Aim The aim of this library is to provide a collection of functional data structures in

Mar 15, 2022