PHP Closures: Comprehensive Guide with Examples
A closure in PHP is an anonymous function that can be assigned to a variable and passed around like any other object. Closures allow you to encapsulate functionality in a callable format, making your code more flexible and reusable. PHP closures are powerful tools in functional programming and are often used in frameworks like Laravel.
1. Defining a Closure
A closure is created using the function keyword without specifying a name.
Basic Example:
$greet = function ($name) {
return "Hello, $name!";
};
echo $greet('John'); // Outputs: Hello, John!
2. Assigning Closures to Variables
Closures can be stored in variables, making them easy to reuse.
Example:
$add = function ($a, $b) {
return $a + $b;
};
echo $add(5, 3); // Outputs: 8
3. Passing Closures as Arguments
Closures can be passed as arguments to other functions.
Example:
function process($callback) {
return $callback('World');
}
echo process(function ($name) {
return "Hello, $name!";
}); // Outputs: Hello, World!
4. Returning Closures from Functions
Functions can return closures.
Example:
function multiplier($factor) {
return function ($value) use ($factor) {
return $value * $factor;
};
}
$double = multiplier(2);
echo $double(10); // Outputs: 20
$triple = multiplier(3);
echo $triple(10); // Outputs: 30
5. Using Closures with use
Closures can inherit variables from the parent scope using the use keyword.
Example:
$prefix = 'Hello';
$sayHello = function ($name) use ($prefix) {
return "$prefix, $name!";
};
echo $sayHello('Alice'); // Outputs: Hello, Alice!
6. Binding Closures to Objects
Closures can be bound to objects using the bindTo or Closure::bind.
Example:
class Greeter {
private $name = 'World';
}
$closure = function () {
return "Hello, $this->name!";
};
$boundClosure = $closure->bindTo(new Greeter());
echo $boundClosure(); // Outputs: Hello, World!
7. Using Closures in Array Functions
Closures are commonly used with array functions like array_map, array_filter, and array_reduce.
Example with array_map:
$numbers = [1, 2, 3, 4];
$doubled = array_map(function ($n) {
return $n * 2;
}, $numbers);
print_r($doubled); // Outputs: [2, 4, 6, 8]
Example with array_filter:
$numbers = [1, 2, 3, 4];
$even = array_filter($numbers, function ($n) {
return $n % 2 === 0;
});
print_r($even); // Outputs: [2, 4]
Example with array_reduce:
$numbers = [1, 2, 3, 4];
$sum = array_reduce($numbers, function ($carry, $item) {
return $carry + $item;
}, 0);
echo $sum; // Outputs: 10
8. Static Closures
You can define a closure as static, meaning it does not inherit the $this context from an enclosing object.
Example:
$staticClosure = static function ($x, $y) {
return $x + $y;
};
echo $staticClosure(3, 5); // Outputs: 8
9. Closures in Classes
Closures can be used as methods or stored as properties in classes.
Storing as Properties:
class Math {
public $add;
public function __construct() {
$this->add = function ($a, $b) {
return $a + $b;
};
}
}
$math = new Math();
$add = $math->add;
echo $add(2, 3); // Outputs: 5
Passing Closures to Methods:
class Calculator {
public function compute($a, $b, callable $operation) {
return $operation($a, $b);
}
}
$calc = new Calculator();
echo $calc->compute(4, 2, function ($a, $b) {
return $a * $b;
}); // Outputs: 8
10. Closures as Middleware
Closures are widely used in middleware for request handling.
$middleware = function ($request, $next) {
$request['middleware'] = 'processed';
return $next($request);
};
$handler = function ($request) {
return $request;
};
$finalRequest = $middleware(['data' => 'test'], $handler);
print_r($finalRequest); // Outputs: ['data' => 'test', 'middleware' => 'processed']
11. Closures in Laravel
Laravel makes extensive use of closures for various tasks:
Routes:
Route::get('/', function () {
return 'Welcome to Laravel!';
});
Middleware:
Route::middleware(function ($request, $next) {
// Modify request
return $next($request);
});
Collections:
$collection = collect([1, 2, 3]);
$doubled = $collection->map(function ($item) {
return $item * 2;
});
print_r($doubled->all()); // Outputs: [2, 4, 6]
12. Advantages of Closures
- Flexibility: Closures provide dynamic behavior by encapsulating logic in a callable format.
- Reusability: They reduce repetition by enabling modular, reusable code.
- Encapsulation: Closures can capture variables from the parent scope for scoped behavior.
13. Limitations of Closures
- Complexity: Overuse of closures can make code harder to read and maintain.
- Debugging: Debugging closures can sometimes be tricky, especially in large, nested applications.
Closures are a versatile and essential feature of PHP, enabling developers to write cleaner, modular, and more flexible code.