Variable Functions
What Are Variable Functions?
In simple terms: A variable function is a function call where the function's name is stored in a variable. When PHP sees parentheses after a variable, it calls the function whose name the variable contains. Technically: If a variable holding a string is followed by (...), PHP looks up a function with that name and calls it. The same mechanism works for methods ($object->$method()), static methods ($class::$method()), and other callables such as closures and [$object, 'method'] arrays.
$fn = 'strtoupper';
echo $fn('php'); // calls strtoupper('php')
Why They Exist
Variable functions let a program decide at runtime which function to call — for example, choosing an export format, a payment handler, or a validation rule based on configuration or data. They are also the foundation of callbacks: passing a function to another function, as array_map() and usort() do.
Basic Usage
Example
<?php
$transform = 'strtoupper';
echo $transform('learn php') . "\n";
$transform = 'ucwords';
echo $transform('learn php') . "\n";
function addStars(string $text): string
{
return "★ $text ★";
}
$transform = 'addStars';
echo $transform('learn php') . "\n";
Output
LEARN PHP
Learn Php
★ learn php ★
How It Works
$transformholds the string'strtoupper'.$transform('learn php')makes PHP call the function named by that string.- Assigning a different name changes which function runs — the calling code stays the same.
- Both built-in and user-defined functions can be called this way.
Choosing a Function From Data: Dispatch Tables
The most practical use of variable functions is a dispatch table: an array that maps keys to the functions that handle them.
<?php
function add(float $a, float $b): float { return $a + $b; }
function subtract(float $a, float $b): float { return $a - $b; }
function multiply(float $a, float $b): float { return $a * $b; }
function calculate(string $operator, float $a, float $b): string
{
$operations = [
'+' => 'add',
'-' => 'subtract',
'*' => 'multiply',
];
if (!isset($operations[$operator])) {
return "Unsupported operator: $operator";
}
$operation = $operations[$operator];
return "$a $operator $b = " . $operation($a, $b);
}
echo calculate('+', 5, 3) . "\n";
echo calculate('*', 4, 2.5) . "\n";
echo calculate('/', 8, 2) . "\n";
Output
5 + 3 = 8
4 * 2.5 = 10
Unsupported operator: /
Why This Pattern Is Safe
- The input (
$operator) is used only as a key in a fixed array. The function names come from your own code. - Unknown operators are rejected before any function is called.
- Adding an operation means adding one line to the table — no growing
if/elseifchain.
Security warning: Never call a function name taken directly from user input, such as
$_GET['action'](). An attacker could call any function available in PHP — for example, functions that delete files or run shell commands. Always map user input to an allow-list of known functions, as shown above.
Variable Methods
The same idea works for methods on objects.
Instance Methods
<?php $date = new DateTimeImmutable('2026-10-09'); $method = 'format'; echo $date->$method('d M Y') . "\n"; $formats = ['Y-m-d', 'l', 'D, j M']; foreach ($formats as $format) { echo $date->$method($format) . "\n"; }Output
09 Oct 2026 2026-10-09 Friday Fri, 9 Oct
$date->$method(...)calls the method whose name is stored in$method.Static Methods
<?php $class = 'DateTimeImmutable'; $factory = 'createFromFormat'; $date = $class::$factory('d/m/Y', '15/10/2026'); echo $date->format('Y-m-d') . "\n";Output
2026-10-15Both the class name and the method name can come from variables.
Callables: Functions as Values
A callable is anything PHP can call. Variable functions are one kind; there are several others:
Callable Form Example Function name string 'strtoupper'Static method string 'DateTimeImmutable::createFromFormat'Object + method array [$date, 'format']Class + static method array ['DateTimeImmutable', 'createFromFormat']Closure (anonymous function) function ($x) { ... }orfn($x) => ...First-class callable (PHP 8.1+) strtoupper(...),$date->format(...)Invokable object An object of a class with an __invoke()methodExample
<?php $date = new DateTimeImmutable('2026-10-09'); $dayName = [$date, 'format']; echo $dayName('l') . "\n"; $upper = 'strtoupper'; $names = ['asha', 'bala']; print_r(array_map($upper, $names)); var_dump(is_callable('strtoupper')); var_dump(is_callable('noSuchFunction')); var_dump(is_callable([$date, 'format']));Output
Friday Array ( [0] => ASHA [1] => BALA ) bool(true) bool(false) bool(true)
[$date, 'format']is an array callable: calling it runs$date->format('l').array_map()accepts any callable, including a function name string.is_callable()checks whether a value can be called — useful before calling a dynamically chosen function. The modern way to create callables from existing functions is first-class callable syntax (strtoupper(...)), which IDEs and static analysis tools understand better than strings. See First-class Callable Syntax.
call_user_func()andcall_user_func_array()These functions call any callable:
<?php echo call_user_func('str_repeat', 'ab', 3) . "\n"; echo call_user_func_array('max', [4, 9, 2]) . "\n";Output
ababab 9In modern PHP, the direct forms are usually preferred:
Older Form Modern Equivalent call_user_func($fn, $a, $b)$fn($a, $b)call_user_func_array($fn, $args)$fn(...$args)
What Cannot Be Called Dynamically
Language constructs are not functions, so they cannot be called through a variable:
echo,isset,empty,unset,include,require,list, andexit/die(in PHP versions before 8.4, whereexitbecame a real function).<?php $output = 'echo'; try { $output('Hello'); } catch (Error $e) { echo get_class($e) . ": " . $e->getMessage() . "\n"; }Output
Error: Call to undefined function echo()Wrap such constructs in a real function or closure if you need to pass them around:
$output = fn(string $s) => print $s;. Calling a name that does not exist produces the same kind of error ("Call to undefined function ..."), which is why dynamic calls should be checked with an allow-list oris_callable().
Practical Example: Export Formats
<?php function exportCsv(array $rows): string { $lines = [implode(',', array_keys($rows[0]))]; foreach ($rows as $row) { $lines[] = implode(',', $row); } return implode("\n", $lines); } function exportJson(array $rows): string { return json_encode($rows); } function export(array $rows, string $format): string { $exporters = [ 'csv' => 'exportCsv', 'json' => 'exportJson', ]; $exporter = $exporters[strtolower($format)] ?? throw new InvalidArgumentException("Unsupported format: $format"); return $exporter($rows); } $rows = [ ['id' => 1, 'name' => 'Asha'], ['id' => 2, 'name' => 'Bala'], ]; echo export($rows, 'csv') . "\n\n"; echo export($rows, 'JSON') . "\n";Output
id,name 1,Asha 2,Bala [{"id":1,"name":"Asha"},{"id":2,"name":"Bala"}]Step-by-Step Explanation
- Each format has its own small function with the same signature: it receives rows and returns a string.
export()maps the requested format (case-insensitively) to a function name. Unknown formats throw an exception —throwcan be used as an expression after??since PHP 8.0.$exporter($rows)calls the selected function.- Adding an XML or Excel export later only requires a new function and one new table entry. This simplified CSV writer does not handle commas or quotes inside values; real code should use
fputcsv()(see Concatenate Strings). In object-oriented code, the same idea is usually implemented with classes that share an interface (see PHP Interfaces).
Common Mistakes
Calling User-Supplied Function Names
Effect: Attackers can execute arbitrary functions. Fix: Map input to an allow-list of known callables.
Calling Language Constructs Dynamically
Effect: "Call to undefined function echo()". Fix: Wrap the construct in a function or closure.
Typos in Function Name Strings
Effect: Runtime error, invisible to editors and static analysis. Fix: Prefer first-class callables (
strtoupper(...)) or closures, which tools can check.Overusing Dynamic Calls
Effect: "Find usages" and refactoring tools cannot see which functions are called, and code becomes hard to follow. Fix: Use dynamic calls only where runtime selection is genuinely needed.
Best Practices
- Use dispatch tables (allow-lists) to choose functions based on data.
- Check dynamic callables with
is_callable()when the source is not fully controlled.- Prefer
$fn(...$args)overcall_user_func_array().- Prefer closures and first-class callable syntax over function-name strings in new code.
- Keep handler functions consistent in signature so they are interchangeable. Official reference: https://www.php.net/manual/en/functions.variable-functions.php Displaying