Before PHP 8.1, passing a function as a callback meant writing its name as a string or an array. Both are easy to mistype, and editors cannot check them.
array_map("strtoupper", $names); // a string
array_map([$formatter, "money"], $prices); // an array
First-class callable syntax replaces them with a real call that has (...) in place of the arguments. You get a Closure object.
<?php
$names = ["ana", "ben"];
$upper = array_map(strtoupper(...), $names);
echo implode(", ", $upper);
ANA, BEN
For functions
<?php
function double(int $n): int
{
return $n * 2;
}
$fn = double(...);
echo $fn(21) . "\n";
echo get_class($fn);
42
Closure
For object methods
<?php
class Formatter
{
public function __construct(private string $symbol) {}
public function money(float $amount): string
{
return $this->symbol . number_format($amount, 2);
}
}
$formatter = new Formatter("Rs. ");
$callback = $formatter->money(...);
echo implode(", ", array_map($callback, [10, 2500]));
Rs. 10.00, Rs. 2,500.00
The closure remembers which object it came from.
For static methods
<?php
class Text
{
public static function shout(string $s): string
{
return strtoupper($s) . "!";
}
}
$shout = Text::shout(...);
echo $shout("hello");
HELLO!
Why it is better
| Old way | New way |
|---|---|
"strtoupper" (a string) | strtoupper(...) |
[$obj, "method"] (an array) | $obj->method(...) |
["Class", "method"] | Class::method(...) |
| Typos found when the code runs | Typos caught by PHP and your editor |
| Visibility problems appear late | Respects the visibility at the place you write it |
Pass a callable to your own function
<?php
function applyAll(array $items, callable $fn): array
{
return array_map($fn, $items);
}
print_r(applyAll([" a ", " b"], trim(...)));
Array
(
[0] => a
[1] => b
)
It is not the same as calling the function
strlen(...) does not call strlen. It creates a callable. strlen("abc") calls it.
Combine with the pipe in PHP 8.5
In PHP 8.5, first-class callables pair with the new pipe operator |>. See PHP 8.5.