PHPAnonymous Functions

Anonymous Functions

An anonymous function is a function with no name, defined inline and usually handed straight to whatever needs it. PHP has supported them since version 5.3, and they show up constantly as callback arguments to functions like `array_map`, `array_filter`, and `usort` — anywhere a "small piece of logic" needs to be passed around as a value rather than declared with `function myFunction() ` somewhere else in the file. Under the hood, an anonymous function is really an instance of the built-in `Closure` class, which is why you will sometimes see the terms "anonymous function" and "closure" used loosely as synonyms.
Assigning an anonymous function to a variable

The most basic form looks just like a regular function definition, except there is no name between function and the parameter list. You capture the result in a variable, and that variable becomes callable.

A callable variable

PHP
<?php
$greet = function ($name) {
    return "Hello, {$name}!";
};

echo $greet("Priya");
echo "\n";
echo gettype($greet);
Hello, Priya!
object

That last line is worth noticing: $greet is not a string containing code, it is an object of type Closure. That is what lets PHP call it with $greet(...), pass it to other functions, and even attach it to a class instance later on.

Anonymous functions as callback arguments

The main reason anonymous functions exist is to be passed directly as an argument, without ever being stored in a named variable first. array_map is a good starting example: it applies a callback to every element of an array and returns a new array of the results.

array_map with an inline anonymous function

PHP
<?php
$prices = [10, 25, 40];

$withTax = array_map(function ($price) {
    return round($price * 1.13, 2);
}, $prices);

print_r($withTax);
Array
(
    [0] => 11.3
    [1] => 28.25
    [2] => 45.2
)

array_filter follows the same pattern, but the callback returns a boolean: true keeps the element, false drops it.

array_filter with an inline anonymous function

PHP
<?php
$numbers = [3, 8, 12, 15, 21, 30];

$evens = array_filter($numbers, function ($n) {
    return $n % 2 === 0;
});

print_r($evens);
Array
(
    [1] => 8
    [2] => 12
    [5] => 30
)
array_filter keeps original keys
Notice the output keys are `1`, `2`, and `5`, not `0`, `1`, `2`. `array_filter` preserves the original array keys instead of renumbering them. If you need a clean, zero-based array afterwards, pipe the result through `array_values()`.
Sorting with usort and a comparator

usort sorts an array in place using a comparator callback you supply. The callback receives two elements, $a and $b, and must return a negative number if $a should come first, a positive number if $b should come first, and zero if they are equal. Anonymous functions are the natural fit here because the comparison logic is usually specific to one call site.

Sorting an array of associative arrays by age

PHP
<?php
$people = [
    ['name' => 'Marco', 'age' => 34],
    ['name' => 'Aisha', 'age' => 22],
    ['name' => 'Devon', 'age' => 41],
];

usort($people, function ($a, $b) {
    return $a['age'] <=> $b['age'];
});

foreach ($people as $person) {
    echo "{$person['name']}: {$person['age']}\n";
}
Aisha: 22
Marco: 34
Devon: 41

The spaceship operator <=> is doing the heavy lifting there — it compares two values and returns -1, 0, or 1, which is exactly the contract usort expects. Writing your own if/else comparison logic by hand works too, but <=> is shorter and less error-prone for simple numeric or string comparisons.

Immediately-invoked function expressions (IIFEs)

Sometimes you want to run a block of code once, immediately, without polluting the surrounding scope with temporary variables or a named function that never gets reused. Wrapping the anonymous function in parentheses and calling it right away — the IIFE pattern — solves that.

An IIFE that keeps a helper variable out of the outer scope

PHP
<?php
$config = (function () {
    $defaults = ['timeout' => 30, 'retries' => 3];
    $overrides = ['timeout' => 60];

    return array_merge($defaults, $overrides);
})();

print_r($config);
// $defaults and $overrides never leak into this scope
Array
(
    [timeout] => 60
    [retries] => 3
)

IIFEs are far less common in PHP than in JavaScript, since PHP files are usually included as whole scripts rather than concatenated together, but the pattern is still useful for one-off setup logic where you want strong scoping guarantees.

Anonymous functions cannot see outer variables by default
No automatic access to the enclosing scope
Unlike some languages, an anonymous function in PHP does **not** automatically see variables from the scope it was defined in. Trying to use `$taxRate` inside the callback below without importing it raises an "Undefined variable" warning and treats it as `null`.

Forgetting to import an outer variable

PHP
<?php
$taxRate = 0.13;

$withTax = array_map(function ($price) {
    return $price * (1 + $taxRate); // $taxRate is NOT visible here
}, [100, 200]);

print_r($withTax);
Warning: Undefined variable $taxRate in ... on line 5
Array
(
    [0] => 100
    [1] => 200
)

Fixing that requires the use ($taxRate) clause, which is covered in full on the Closures & use() page — that is the mechanism PHP gives you to deliberately pull outer variables into an anonymous function's own scope.

  • Anonymous functions are objects of type Closure, which is why gettype() reports object rather than something like function.

  • array_map transforms every element and returns a same-length array; array_filter removes elements and keeps original keys.

  • usort needs a comparator that returns negative, zero, or positive — the spaceship operator <=> is the idiomatic way to produce that.

  • An IIFE — (function () { ... })() — runs once immediately and keeps its internal variables from leaking into the surrounding scope.

Tip
If a callback is longer than two or three lines, consider extracting it into a named function or a static method instead of leaving it anonymous inline. Anonymous functions are great for short, focused logic; once they grow, a name and a stable location make the code far easier to read and to unit test in isolation.