PHPCallbacks & Callable

Callbacks & Callable

PHP does not have a single dedicated "function type." Instead, it recognizes several different shapes of value as "invokable," and groups them all under the pseudo-type callable. When a function's parameter is type-hinted callable, PHP will accept a plain string function name, a Closure object, an array describing an object-and- method pair, or an object with an __invoke() method. Understanding these forms matters because a lot of PHP's standard library — array_map, usort, call_user_func, and many others — is built entirely around accepting a callable rather than a fixed function.

String callables: calling a function by name

The simplest callable is just the name of a function, as a string. PHP looks it up at call time and invokes it.

A built-in function name as a callable

PHP
<?php
function applyCallback(callable $fn, string $value): string {
    return $fn($value);
}

echo applyCallback('strtoupper', 'hello world');
HELLO WORLD

This works for any user-defined function too, not just built-ins: applyCallback('myCustomFunction', $value) behaves the same way as long as myCustomFunction exists somewhere PHP can see it.

Array callables for methods

To reference a method rather than a standalone function, PHP uses a two-element array. For an instance method, the first element is the object and the second is the method name as a string. For a static method, the first element is the class name (or ClassName::class) instead of an object instance.

Instance-method and static-method array callables

PHP
<?php
class PriceFormatter {
    private string $currency;

    public function __construct(string $currency) {
        $this->currency = $currency;
    }

    public function format(float $amount): string {
        return number_format($amount, 2) . ' ' . $this->currency;
    }

    public static function formatCad(float $amount): string {
        return number_format($amount, 2) . ' CAD';
    }
}

$formatter = new PriceFormatter('EUR');

// Instance method: [$object, 'methodName']
$instanceCallable = [$formatter, 'format'];
echo $instanceCallable(1999.5), "\n";

// Static method: [ClassName::class, 'staticMethod']
$staticCallable = [PriceFormatter::class, 'formatCad'];
echo $staticCallable(1999.5), "\n";
1,999.50 EUR
1,999.50 CAD

A static method callable can also be written as the single string 'PriceFormatter::formatCad', which is equivalent to the two-element array form — both are recognized as valid callable values.

call_user_func() and call_user_func_array()

Sometimes you have a callable value and a set of arguments computed separately, and you want to invoke the callable dynamically rather than writing $callable(...) directly (which also works, but call_user_func reads more explicitly in some contexts, such as inside generic dispatch code). call_user_func() takes the callable plus each argument individually; call_user_func_array() takes the callable plus a single array of arguments, which is the better choice when the argument count varies at runtime.

call_user_func vs call_user_func_array

PHP
<?php
function add(int $a, int $b, int $c = 0): int {
    return $a + $b + $c;
}

echo call_user_func('add', 2, 3), "\n";

$args = [5, 10, 15];
echo call_user_func_array('add', $args), "\n";
5
30

call_user_func_array shines when the arguments come from somewhere dynamic — form input, a config array, another function's return value — and you do not know at the time you write the code exactly how many there will be.

Combining array callables with call_user_func_array

Dispatching to a method with a dynamic argument list

PHP
<?php
class Logger {
    public function log(string $level, string $message, string $context = ''): string {
        return "[{$level}] {$message} {$context}";
    }
}

$logger = new Logger();
$callable = [$logger, 'log'];
$args = ['WARN', 'Disk usage high', '(87%)'];

echo call_user_func_array($callable, $args);
[WARN] Disk usage high (87%)
First-class callable syntax (PHP 8.1+)

PHP 8.1 introduced a cleaner way to turn an existing named function or method directly into a Closure, without the string or array indirection: append (...) to the reference instead of calling it. This is called first-class callable syntax.

strlen(...) instead of 'strlen'

PHP
<?php
$lengthOf = strlen(...);

echo $lengthOf('Hello'), "\n";

// Works for methods too
class Greeter {
    public function greet(string $name): string {
        return "Hi, {$name}!";
    }
}

$greeter = new Greeter();
$greet = $greeter->greet(...);

echo $greet('Sam');
5
Hi, Sam!

The advantage over 'strlen' or [$greeter, 'greet'] is that strlen(...) and $greeter->greet(...) are checked by IDEs and static analysis tools the same way an ordinary function call would be, catching typos in the name or a mismatched argument count before the code ever runs.

A typo in a string or array callable fails at call time, not at definition time
`'strtoupperr'` (with an extra "r") or `[$obj, 'formatt']` will pass right through PHP's parser without complaint — they are just strings and arrays. The error only surfaces when the callable is actually invoked, as an "Uncaught Error: Call to undefined method" or similar. First-class callable syntax and direct `$obj->method(...)` calls do not have this gap, since the method name is validated as real code, not as arbitrary string data.
  • callable accepts: a function name string, a Closure, [$object, 'method'], [ClassName::class, 'staticMethod'], and 'ClassName::staticMethod'.

  • call_user_func($callable, ...$args) invokes with a fixed, individually-listed argument list.

  • call_user_func_array($callable, $argsArray) invokes with a variable-length argument list packed into an array.

  • PHP 8.1's func(...) first-class callable syntax converts any named function or method reference into a real Closure with compile-time name checking.

is_callable() as a guard
Before invoking a callable that came from user input or configuration (rather than a value you wrote yourself), check `is_callable($value)` first. It returns `true` or `false` without throwing, letting you fail gracefully instead of crashing on an undefined function or method.
Tip
Prefer first-class callable syntax — `func(...)` or `$obj->method(...)` — over string or array callables in new PHP 8.1+ code. It gets full IDE autocompletion, gets flagged by static analysis when the target is renamed or removed, and reads more clearly than a bare string or a two-element array.