Functional Programming in PHP: Advanced Level
PHP is traditionally associated with imperative and object-oriented styles, but the modern language (especially from version 7.4 and above) provides powerful tools for applying the functional paradigm. In this article, we will examine advanced concepts of functional programming (FP) in PHP that will help you write more predictable, testable, and expressive code.
1. Pure Functions and Data Immutability
At the core of FP are pure functions — functions that:
- Depend only on their arguments (do not use global variables or state outside the scope);
- Do not cause side effects (do not modify external data, do not write to files, do not send HTTP requests);
- For the same input data, always return the same result.
In PHP, data immutability is actively used to ensure function purity. Instead of mutating existing arrays or objects, copies with changes are created.
<?php// Impure function (uses a global array)$globalData = [1, 2, 3];function addElementImpure($value) { global $globalData; $globalData[] = $value; // Side effect return $globalData;}
// Pure function (returns a new array)function addElementPure(array $data, $value): array { $newData = $data; $newData[] = $value; return $newData;}
$original = [1, 2, 3];$modified = addElementPure($original, 4);// $original remains [1, 2, 3], $modified = [1, 2, 3, 4]?>2. Closures and Variable Capture
Closures in PHP are anonymous functions that can capture variables from the parent scope using the use keyword. This is the foundation for creating higher-order functions.
It is important to distinguish between capture by value (default) and by reference (&use). In the context of FP, capture by value is preferable to avoid breaking purity.
<?php$multiplier = 3;
// Closure capturing $multiplier by value$multiply = function ($value) use ($multiplier) { return $value * $multiplier;};
echo $multiply(5); // 15
// Example of a higher-order function returning a closurefunction createGreeter(string $greeting): Closure { return function (string $name) use ($greeting) { return "{$greeting}, {$name}!"; };}
$sayHello = createGreeter('Hello');echo $sayHello('World'); // Hello, World!?>3. Currying and Partial Application
Currying is the transformation of a function that takes multiple arguments into a sequence of functions, each taking a single argument. Partial application is fixing some arguments to obtain a new function with fewer parameters.
PHP does not have built-in support for currying, but it can be implemented using closures.
<?php// Regular functionfunction add(int $a, int $b, int $c): int { return $a + $b + $c;}
// Curried version$curriedAdd = function (int $a) { return function (int $b) use ($a) { return function (int $c) use ($a, $b) { return $a + $b + $c; }; };};
echo $curriedAdd(1)(2)(3); // 6
// Partial application using a helper functionfunction partial(callable $fn, ...$fixedArgs): Closure { return function (...$remainingArgs) use ($fn, $fixedArgs) { return $fn(...array_merge($fixedArgs, $remainingArgs)); };}
$addFive = partial('add', 2, 3);echo $addFive(10); // 15 (2 + 3 + 10)?>4. Function Composition and Pipelines
Function composition allows you to combine several simple functions into one complex one, passing the resu