Functional Programming in PHP: Advanced Level
\n\nFunctional programming (FP) is a paradigm in which computation is treated as the evaluation of mathematical functions, avoiding changing state and mutable data. Although PHP was not originally designed as a purely functional language, starting from version 7.4 and especially in PHP 8.x, it has gained powerful tools for writing code in a functional style. In this article, we will explore advanced FP concepts in PHP: from higher-order functions to monads, with practical examples and recommendations.
\n\n1. Higher-Order Functions and Closures
\n\nHigher-order functions are functions that take other functions as arguments or return them. In PHP, this is implemented through anonymous functions (closures) and built-in functions like array_map, array_filter, array_reduce.
Example: callback function for filtering
\n\n<?php\n$numbers = [1, 2, 3, 4, 5, 6];\n\n// Higher-order function\n$filterEven = function(array $items, callable $callback): array {\n $result = [];\n foreach ($items as $item) {\n if ($callback($item)) {\n $result[] = $item;\n }\n }\n return $result;\n};\n\n// Anonymous predicate function\n$isEven = fn($n) => $n % 2 === 0;\n\n$evenNumbers = $filterEven($numbers, $isEven);\n// Result: [2, 4, 6]\nprint_r($evenNumbers);\n?>\n\n\nExample: function factory (closure with state)
\n\n<?php\nfunction createMultiplier(float $factor): callable {\n // Closure "remembers" $factor\n return fn($number) => $number * $factor;\n}\n\n$double = createMultiplier(2);\n$triple = createMultiplier(3);\n\necho $double(5); // 10\necho $triple(5); // 15\n?>\n\n\nClosures in PHP allow capturing variables from the outer scope via use (in PHP 7.4+ you can use arrow functions fn). This is the foundation for building currying and partial application.
2. Currying and Partial Application
\n\nCurrying is the transformation of a function with multiple arguments into a sequence of functions with a single argument. Partial application is fixing a portion of a function's arguments. PHP has no built-in support, but it is easy to implement.
\n\nExample: manual currying
\n\n<?php\n// Regular function\nfunction add(int $a, int $b): int {\n return $a + $b;\n}\n\n// Curried version\n$curriedAdd = function(int $a): callable {\n return function(int $b) use ($a): int {\n return $a + $b;\n };\n};\n\n$addFive = $curriedAdd(5);\necho $addFive(3); // 8\n?>\n\n\nExample: universal currying function
\n\n<?php\nfunction curry(callable $fn, int $arity = null): callable {\n $reflection = new ReflectionFunction($fn);\n $arity = $arity ?? $reflection->getNumberOfRequiredParameters();\n\n $curry = function(...$args) use ($fn, $arity, &$curry) {\n if (count($args) >= $arity) {\n return $fn(...$args);\n }\n return function(...$nextArgs) use ($fn, $args, $arity, $curry) {\n return $curry(...array_merge($args, $nextArgs));\n };\n };\n\n return $curry;\n}\n\n$add = function(int $a, int $b, int $c): int {\n return $a + $b + $c;\n};\n\n$curriedAdd = curry($add);\n$result = $curriedAdd(1)(2)(3); // 6\necho $result;\n?>\n\n\nCurrying is especially useful for function composition and creating specialized versions of general functions.
\n\n3. Function Composition and Functional Patterns
\n\nFunction composition is creating a new function by sequentially applying multiple functions. The result of one function is passed as input to the next.
\n\nExample: left-to-right composition (pipe)