As your scripts grow, you will notice the same few lines appearing again and again: formatting a price, checking an email address, calculating tax. A function wraps such code in a named, reusable block. You write it once, test it once and call it wherever you need it. You have already used many built-in functions, such as strlen() and count(). Now you will write your own PHP functions.
Defining and calling PHP functions
A function is defined with the function keyword, a name, a list of parameters in brackets and a body in curly braces. The return statement sends a value back to the caller and ends the function.
<?php
declare(strict_types=1);
function formatPrice(float $amount, string $currency = "Rs."): string
{
return $currency . " " . number_format($amount, 2);
}
echo formatPrice(1499), "\n";
echo formatPrice(24.5, "USD"), "\n";
echo formatPrice(currency: "EUR", amount: 12), "\n";Rs. 1,499.00 USD 24.50 EUR 12.00
Let us read the first line slowly:
float $amountis a typed parameter. The function only accepts a number. With strict types on, an int is still allowed for a float parameter (it is widened safely), but a string is rejected.string $currency = "Rs."has a default value, so callers may leave it out. Parameters with defaults should come after the required ones.: stringafter the brackets is the return type. PHP checks that the function really returns a string.
The last call uses named arguments (PHP 8). You write the parameter name, a colon and the value, so the order no longer matters and the call explains itself. Named arguments are especially helpful for functions with several optional parameters.
Tip: Function names are not case-sensitive in PHP, but always call a function exactly as it was defined. Use camelCase verbs that describe the action, such as calculateGst() or sendInvoice().
Why types matter
Typed parameters and return types act as a contract. Anyone reading function isAdult(int $age): bool knows exactly what goes in and what comes out without reading the body. Combined with declare(strict_types=1);, which you met in PHP Data Types, mistakes cause a clear TypeError at the point of the call instead of strange results later.
A few special types are worth knowing:
| Type | Meaning |
|---|---|
void | The function returns nothing (it only does something, such as printing). |
?string | Nullable: a string or null. |
int|float | Union type: either of the listed types. |
array | Any array. |
mixed | Any type at all – use sparingly, because it tells the reader very little. |
<?php
declare(strict_types=1);
function findPincode(string $city): ?string
{
$pincodes = [
"Puducherry" => "605001",
"Chennai" => "600001",
"Madurai" => "625001",
];
return $pincodes[$city] ?? null;
}
function describeDelivery(string $city): string
{
$pin = findPincode($city);
if ($pin === null) {
return "Sorry, we do not deliver to $city yet.";
}
return "Delivering to $city ($pin).";
}
echo describeDelivery("Madurai"), "\n";
echo describeDelivery("Hosur");Delivering to Madurai (625001). Sorry, we do not deliver to Hosur yet.
describeDelivery() uses a guard clause: it deals with the missing case first and returns early, so the normal path is not buried inside an else. Small functions that do one job, call each other and return early are much easier to test and change.
Variable scope
Variables created inside a function are local: they exist only while the function runs and are invisible outside. In the same way, variables defined outside a function are not visible inside it. This surprises people coming from JavaScript, but it is a good thing: a function cannot accidentally change your other variables.
<?php
$shopName = "Kovai Crafts";
function greet(string $customer): string
{
// $shopName is not visible here, so pass it in as a parameter instead
$message = "Vanakkam, $customer!";
return $message;
}
echo greet("Divya"), "\n";
var_dump(isset($message)); // $message only existed inside greet()Vanakkam, Divya! bool(false)
Watch out: You may see the global keyword in old tutorials to reach outside variables from a function. Avoid it. Pass values in as parameters and return results instead; your functions stay predictable and easy to reuse.
Anonymous and arrow functions
Sometimes you need a small function only once, for example to tell array_map() what to do with each item. You can write it inline without a name. The short arrow function syntax fn($x) => expression returns the expression automatically and can read variables from the surrounding code.
<?php
$prices = [120, 450, 80, 999];
$gstRate = 0.18;
$withGst = array_map(fn(int $p): float => round($p * (1 + $gstRate), 2), $prices);
$expensive = array_filter($prices, fn(int $p): bool => $p > 100);
echo implode(", ", $withGst), "\n";
echo implode(", ", $expensive);141.6, 531, 94.4, 1178.82 120, 450, 999
Notice that the arrow function used $gstRate from outside without any extra code. Regular anonymous functions need use ($gstRate) to do the same. You will use these helpers a lot in the next lesson, PHP Arrays.
Organising your PHP functions
In a real project, you do not copy the same function into every page. You collect related functions in one file, such as helpers.php, and load it wherever it is needed with require_once, which is covered in PHP Include and Files. Try to keep each function short and focused on one task. A good test: if you cannot describe what a function does in one sentence without the word “and”, it probably wants to be split into two. PHP functions that only work with their parameters and return a result, without printing or changing anything else, are the easiest to test and reuse.
