Lesson 8 of 12

PHP Functions

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";
Output
Rs. 1,499.00
USD 24.50
EUR 12.00

Let us read the first line slowly:

  • float $amount is 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.
  • : string after 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:

TypeMeaning
voidThe function returns nothing (it only does something, such as printing).
?stringNullable: a string or null.
int|floatUnion type: either of the listed types.
arrayAny array.
mixedAny 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");
Output
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()
Output
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);
Output
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.

Further reading

Key takeaways

  • Define functions with function name(type $param): returnType { ... } and send results back with return.
  • Default values make parameters optional; named arguments make calls readable and order-independent.
  • Use declare(strict_types=1); with typed parameters and returns to catch mistakes early.
  • Nullable (?string), union (int|float) and void types describe special cases.
  • Variables inside a function are local; pass data in with parameters instead of using global.
  • Arrow functions fn($x) => … are handy for array_map() and array_filter().

Quick quiz

Check what you learned – pick an answer.

1. What does the ?int return type mean?

2. Given function area(int $width, int $height): int, which call uses named arguments correctly?

3. A variable $total is created outside a function. What happens if the function reads $total without receiving it as a parameter?

Practice exercise

Write a function calculateEmi(float $principal, float $annualRate, int $months): float that returns the monthly loan instalment rounded to 2 decimals, using the formula P × r × (1 + r)^n ÷ ((1 + r)^n − 1), where r is the monthly rate (annual rate ÷ 12 ÷ 100). Print the EMI for Rs. 1,00,000 at 12% for 12 months.

Show a hint

Use ** for the power. The expected answer is 8884.88.

Show the solution
<?php
declare(strict_types=1);

function calculateEmi(float $principal, float $annualRate, int $months): float
{
    $r = $annualRate / 12 / 100;
    $factor = (1 + $r) ** $months;
    return round($principal * $r * $factor / ($factor - 1), 2);
}

echo calculateEmi(100000, 12, 12); // 8884.88

Progress is saved in this browser only.