A function is a named block of steps you can run whenever you need it. In PHP:
<?php
function greet(string $name): string {
return "Hello, $name!";
}
echo greet("Ada"); // Hello, Ada!
?>The string before $name and after the colon are type declarations. They are optional, and they catch a category of bug for free.
Parameters and defaults#
<?php
function price(float $amount, float $taxRate = 0.20, string $currency = "£"): string {
$total = $amount * (1 + $taxRate);
return $currency . number_format($total, 2);
}
echo price(100); // £120.00
echo price(100, 0.05); // £105.00
echo price(100, currency: "$"); // $120.00 — named argument
?>Named arguments (PHP 8+) mean you can skip a middle parameter without passing its default again. They also make a call readable at a glance — price(100, currency: "$") says more than price(100, 0.20, "$").
Parameters with defaults must come after those without.
Type declarations#
<?php
declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
add(2, 3); // 5
add("2", "3"); // TypeError with strict_types, 5 without
?>Without strict_types, PHP quietly converts "2" to 2. With it, you get an immediate error naming the problem. Put declare(strict_types=1); at the top of every file — the failures become loud and early instead of subtle and late.
Useful types: int, float, string, bool, array, ?string (string or null), void, and union types like int|float.
Return early#
Handling awkward cases first keeps the main logic out of nested braces:
<?php
function discountFor(?array $user): int {
if ($user === null) return 0;
if (!$user["isMember"]) return 0;
if ($user["years"] > 5) return 20;
return 10;
}
?>Passing behaviour in#
This is what “customising behaviour” really means: a function that takes another function, so one piece of code can do different things for different callers.
<?php
$prices = [100, 250, 80];
$withTax = array_map(fn($p) => $p * 1.2, $prices);
$big = array_filter($prices, fn($p) => $p > 90);
$total = array_reduce($prices, fn($sum, $p) => $sum + $p, 0);
?>Arrow functions (fn() =>) automatically see variables from the surrounding scope. The older function () use ($x) {} closure form needs you to list them:
<?php
$minimum = 90;
$big = array_filter($prices, function ($p) use ($minimum) {
return $p > $minimum;
});
?>You can also accept a callable in your own functions:
<?php
function processAll(array $items, callable $step): array {
$out = [];
foreach ($items as $item) {
$out[] = $step($item);
}
return $out;
}
processAll(["a", "b"], strtoupper(...)); // ["A", "B"]
?>Variable numbers of arguments#
<?php
function total(int ...$numbers): int {
return array_sum($numbers);
}
echo total(1, 2, 3); // 6
$values = [1, 2, 3];
echo total(...$values); // spread an array back in
?>Questions people ask#
What is the difference between a function and a method?
A method is a function that belongs to a class and is called on an object: $user->getName(). See OOP in PHP.
Can PHP functions return more than one value?
Return an array and destructure it: [$min, $max] = getRange($numbers);.
What does the ?string type mean?
It allows null as well as a string. Without the question mark, passing null is a type error.
Should every function have type declarations?
Yes, in new code. They document intent, help your editor, and turn silent conversions into visible errors.
Where to go next#
- Arrays and data structures in PHP
- Handling errors and exceptions in PHP
- Functions explained, language-agnostic