PHP: Advanced Functions
You've got the function basics down. This lesson lets you write more flexible, more modern, more PHP 8–style functions — variadic parameters, named arguments, arrow functions — all fruits of PHP's continuous evolution.
1. Variadic Parameters (...$args)
Don't know how many arguments will be passed? Use ... to capture them all into an array:
<?php
function sum(...$numbers): int {
return array_sum($numbers);
}
echo sum(1, 2); // 3
echo sum(1, 2, 3, 4, 5); // 15
echo sum(); // 0
// You can also have fixed parameters before the variadic ones
function sendMessage(string $to, string ...$messages): void {
foreach ($messages as $msg) {
echo "Sent to {$to}: {$msg}<br>";
}
}
sendMessage("John", "Good morning", "How's lunch?", "Good night");
// Sent to John: Good morning
// Sent to John: How's lunch?
// Sent to John: Good night
?>
▶ Example: ... to Spread an Array into Arguments
Output:
6
<?php
function add(int $a, int $b, int $c): int {
return $a + $b + $c;
}
$nums = [1, 2, 3];
echo add(...$nums); // 6 (the array is spread into 3 separate arguments)
// Commonly used with array_push and similar functions
$stack = ["a", "b"];
array_push($stack, ...["c", "d", "e"]);
print_r($stack); // ["a", "b", "c", "d", "e"]
?>
Output:
6
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
)
... works in both directions — in a function definition it packs arguments into an array; at a call site it spreads an array into arguments.
2. Named Arguments (PHP 8.0)
No need to memorize parameter order — pass arguments by name:
▶ Example: Named Arguments
Output:
(no visible output - function defined)
<?php
function createUser(
string $name,
int $age,
string $email = "",
bool $isAdmin = false
): array {
return compact('name', 'age', 'email', 'isAdmin');
}
// Traditional: must follow parameter order
$u1 = createUser("John", 25, "john@example.com", true);
// Named arguments: order doesn't matter — skip parameters with defaults
$u2 = createUser(
name: "Jane",
age: 22,
isAdmin: true
// email uses the default
);
// When a function has many parameters, named arguments dramatically improve readability
setcookie(
name: "theme",
value: "dark",
expires_or_options: time() + 3600,
httponly: true
);
?>
Output:
Array
(
[name] => Jane
[age] => 22
[email] =>
[isAdmin] => 1
)
createUser(name: "John", age: 25) is instantly clear.
3. Passing by Reference (&$var)
By default, PHP passes function arguments by value — modifying a parameter inside the function doesn't affect the outer variable. Add & to pass by reference:
<?php
// Pass by value (default): internal modification doesn't affect the outside
function addTen(int $n): void {
$n += 10;
}
$x = 5;
addTen($x);
echo $x; // 5 (unchanged)
// Pass by reference: internal modification directly affects the outer variable
function addTenRef(int &$n): void {
$n += 10;
}
addTenRef($x);
echo $x; // 15 (changed!)
?>
| Pass by Value | Pass by Reference | |
|---|---|---|
| Syntax | function f($x) |
function f(&$x) |
| Internal modification | Doesn't affect outer variable | Affects the outer variable |
| Best for | Most situations | When you need to "return" multiple values |
sort(&$arr)).
4. Variable Scope
In PHP, the inside of a function and the outside are two separate worlds:
<?php
$globalVar = "I'm outside";
function test(): void {
// echo $globalVar; // Warning: Undefined variable
// Functions can't directly access outer variables
$localVar = "I'm inside";
echo $localVar; // OK
}
test();
// echo $localVar; // Warning: can't access the function's inner variable either
?>
(1) Using global to Break the Barrier
<?php
$counter = 0;
function increment(): void {
global $counter; // Declare: I want to use the global variable
$counter++;
}
increment();
increment();
echo $counter; // 2
?>
(2) The $GLOBALS Superglobal Array
<?php
$name = "John";
function showName(): void {
echo $GLOBALS['name']; // John
}
showName();
?>
global keyword is a necessary evil — know it exists, but avoid using it whenever possible. Global variables make code hard to test and maintain. Most of the time, pass data into functions as parameters.
5. Static Variables
A static variable inside a function retains its value between calls:
<?php
function getNextId(): int {
static $id = 0;
$id++;
return $id;
}
echo getNextId(); // 1
echo getNextId(); // 2
echo getNextId(); // 3
// A static variable is only initialized once — on the first call
// Subsequent calls preserve the previous value
?>
6. Anonymous Functions (Closures)
Functions don't need names — they can be assigned to variables and passed as arguments:
<?php
// Anonymous function assigned to a variable
$greet = function(string $name): string {
return "Hello, {$name}!";
};
echo $greet("John"); // Hello, John!
// Passed as an argument to another function (callback)
$numbers = [1, 2, 3, 4, 5];
$doubled = array_map(function($n) {
return $n * 2;
}, $numbers);
print_r($doubled); // [2, 4, 6, 8, 10]
?>
(1) The use Keyword for Anonymous Functions
If an anonymous function needs an outer variable, you must import it with use:
<?php
$prefix = "User";
// ❌ Wrong: $prefix is not visible inside the anonymous function
// $greet = function($name) {
// return "{$prefix}: {$name}";
// };
// ✅ Correct: import the outer variable with use
$greet = function($name) use ($prefix): string {
return "{$prefix}: {$name}";
};
echo $greet("John"); // User: John
// Import by reference (allows modifying the outer variable)
$count = 0;
$inc = function() use (&$count): void {
$count++;
};
$inc(); $inc();
echo $count; // 2
?>
7. Arrow Functions (PHP 7.4+)
Arrow functions fn() => are the ultra-concise version of single-expression anonymous functions. They automatically capture outer variables (no use needed):
<?php
$factor = 3;
// Anonymous function syntax
$anon = function($n) use ($factor) {
return $n * $factor;
};
// Arrow function syntax (automatically captures $factor)
$arrow = fn($n) => $n * $factor;
echo $anon(5); // 15
echo $arrow(5); // 15
// The golden pair with array_map
$nums = [1, 2, 3, 4, 5];
$tripled = array_map(fn($n) => $n * $factor, $nums);
print_r($tripled); // [3, 6, 9, 12, 15]
?>
map / filter / usort callbacks.
8. Callbacks and the callable Type
PHP lets you use function name strings, anonymous functions, and object methods as callbacks:
<?php
// Method 1: function name as a string
function double(int $n): int {
return $n * 2;
}
$result = array_map('double', [1, 2, 3]);
// 'double' (with quotes) — the function name string is passed to array_map
// Method 2: anonymous function
$result = array_map(fn($n) => $n * 3, [1, 2, 3]);
// Method 3: callable type declaration
function apply(callable $fn, array $data): array {
return array_map($fn, $data);
}
$result = apply('double', [1, 2, 3]); // ✅
$result = apply(fn($n) => $n * 2, [1, 2, 3]); // ✅
// apply(123, [1, 2, 3]); // TypeError!
?>
▶ Example: Closure with use for Tax Calculation
Output:
value
value
<?php
function makeTaxCalculator(float $rate): callable {
return function(float $price) use ($rate): float {
return round($price * (1 + $rate), 2);
};
}
$taxUK = makeTaxCalculator(0.20);
$taxJP = makeTaxCalculator(0.10);
echo $taxUK(100); // 120
echo $taxJP(100); // 110
Output:
Output displayed
❓ FAQ
... have in PHP?...$args packs remaining arguments into an array. (2) At a function call, ...$arr spreads an array into individual arguments. sum(...$nums) is spreading; function sum(...$nums) is packing.foo(1, c: 3, b: 2) is valid; foo(a: 1, 2, 3) is not.fn($x) => $x * 2 for single expressions. Use anonymous functions function($x) { ... } for multi-line logic. Arrow functions are more concise and auto-capture outer variables (no use needed).📖 Summary
...$argsvariadic parameters: packs arguments into an array / spreads an array into arguments- Named arguments (PHP 8):
fn(name: "John", age: 25)— skip parameters with defaults &$varpass by reference: function modifies the outer variable (use sparingly)global/$GLOBALSto access global variables inside functionsstaticvariable: retains its value between function calls- Anonymous functions +
use: functions as variables - Arrow functions
fn() => expr: concise callbacks, auto-capture outer variables
📝 Exercises
- Write a function
average(...$numbers): floatthat takes any number of numeric arguments and returns their average. - Use
array_mapand an arrow function to convert every string in an array to uppercase. - Use a static variable to write a
hitCounter()function that returns an incrementing visit count on each call.