Himanshu SharmaSoftware engineer
Let’s talk

PHP · Lesson 19 of 54

Parameters, defaults, named arguments and types

Give PHP function parameters default values and types, call functions with named arguments, accept any number of arguments, and declare return types.

14 minFunctionsUpdated 22 October 2026

Awaiting technical review. This lesson is readable but not yet listed in search engines.

By the end of this lessonWrite functions with typed, optional and named parameters and a declared return type.

Default values

A parameter can have a default value, which is used when the caller leaves that argument out. That makes the parameter optional:

php
<?php
function priceWithTax($price, $rate = 0.18)
{
    return round($price * (1 + $rate), 2);
}

echo priceWithTax(100) . "\n";
echo priceWithTax(100, 0.05) . "\n";
result
118
105

Optional parameters must come after the required ones. A default must be a constant expression, such as a number, a string, an array, null or a constant, not a function call.

Named arguments

Since PHP 8 you can pass arguments by name instead of by position. Named arguments make calls easier to read, and they let you skip optional parameters in the middle:

php
<?php
function formatPrice($amount, $currency = "INR", $decimals = 2, $symbolFirst = true)
{
    $symbols = ["INR" => "₹", "USD" => "$", "GBP" => "£"];
    $number = number_format($amount, $decimals);
    $symbol = $symbols[$currency] ?? $currency . " ";
    return $symbolFirst ? $symbol . $number : $number . " " . $symbol;
}

echo formatPrice(1499) . "\n";
echo formatPrice(1499, decimals: 0) . "\n";
echo formatPrice(amount: 24.5, currency: "GBP") . "\n";
echo formatPrice(24.5, symbolFirst: false, currency: "USD") . "\n";
result
₹1,499.00
₹1,499
£24.50
24.50 $

The second call sets only decimals without repeating the currency. Named arguments can be in any order, and you can mix them with positional ones as long as the positional ones come first. PHP's built-in functions support them too: str_pad(string: "7", length: 3, pad_string: "0", pad_type: STR_PAD_LEFT) is clearer than four bare values.

Parameter types

By default a parameter accepts anything. Adding a type declaration in front of the name tells PHP what is allowed, and PHP checks it on every call:

php
<?php
function lineTotal(float $price, int $quantity): float
{
    return $price * $quantity;
}

echo lineTotal(18.75, 4) . "\n";
echo lineTotal(10, 3) . "\n";
result
75
30

The integer 10 was accepted for the float parameter, because PHP widens integers to floats. In the default "coercive" mode, PHP also converts compatible scalars such as the string "4" to an int. Values that cannot be converted throw a TypeError:

php
<?php
function lineTotal(float $price, int $quantity): float
{
    return $price * $quantity;
}

echo lineTotal(18.75, "four");
result
Fatal error: Uncaught TypeError: lineTotal(): Argument #2 ($quantity) must be of type int, string given, called in /path/to/script.php on line 7 and defined in /path/to/script.php:2
Stack trace:
#0 /path/to/script.php(7): lineTotal(18.75, 'four')
#1 {main}
  thrown in /path/to/script.php on line 2

With declare(strict_types=1); at the top of the file, even "4" is rejected, as shown in Comparisons, == versus === and type juggling.

The types you will use most:

Type Accepts
int, float, string, bool That scalar type
array Any array
?string A string or null (any type can be made nullable with ?)
int|float Either type (a union type)
mixed Anything
callable A function that can be called
A class name, such as DateTime An object of that class

Return types

A return type after the brackets, ): float, declares what the function gives back. PHP checks it when the function returns. void means the function returns nothing, and never means it never returns at all (it always throws or exits):

php
<?php
function logMessage(string $message): void
{
    echo "[log] $message\n";
}

function findDiscount(string $code): ?int
{
    $codes = ["SAVE10" => 10, "SAVE25" => 25];
    return $codes[$code] ?? null;
}

logMessage("Checking coupons");
var_dump(findDiscount("SAVE25"));
var_dump(findDiscount("FREE"));
result
[log] Checking coupons
int(25)
NULL

Types do more than catch mistakes. They document the function: a reader knows from the first line that findDiscount() takes a string and returns an integer or null, and editors use them to warn you as you type.

Any number of arguments

A parameter written with three dots, ...$name, is variadic: it collects all remaining arguments into an array. It must be the last parameter:

php
<?php
function total(float ...$prices): float
{
    return array_sum($prices);
}

echo total(89.5, 18.75, 12) . "\n";
echo total() . "\n";
result
120.25
0

The same three dots do the opposite at the call site: they spread an array into separate arguments.

php
<?php
function total(float ...$prices): float
{
    return array_sum($prices);
}

$cart = [24.99, 14.99, 9.5];
echo total(...$cart) . "\n";
echo max(...$cart) . "\n";
result
49.48
24.99

Passing by reference

Arguments are normally passed by value: the function gets a copy, and changes inside it do not affect the caller's variable. An & before the parameter passes the variable itself, so the function can change it:

php
<?php
function addItem(array &$cart, string $item): void
{
    $cart[] = $item;
}

$cart = ["Mug"];
addItem($cart, "Keyboard");
print_r($cart);
result
Array
(
    [0] => Mug
    [1] => Keyboard
)

Some built-in functions, such as sort(), work this way. In your own code, returning a new value is usually clearer than changing the argument, so use references sparingly.

Common mistakes

  • Putting an optional parameter before a required one. PHP 8 deprecates it, and it makes positional calls confusing.
  • Misspelling a named argument, which is an error: the name must match the parameter exactly.
  • Declaring void and then returning a value, or forgetting to return on some path of a function with a return type.
  • Using a reference where a return value would do.

Exercise

Write discountedPrice(float $price, int $percent = 0, ?float $maxDiscount = null): float. It applies the percentage, but never takes off more than $maxDiscount when that is set. Print the result for (2000), (2000, 10) and (2000, percent: 30, maxDiscount: 400).

Show one possible answer
php
<?php
function discountedPrice(float $price, int $percent = 0, ?float $maxDiscount = null): float
{
    $discount = $price * $percent / 100;
    if ($maxDiscount !== null) {
        $discount = min($discount, $maxDiscount);
    }
    return $price - $discount;
}

echo discountedPrice(2000) . "\n";
echo discountedPrice(2000, 10) . "\n";
echo discountedPrice(2000, percent: 30, maxDiscount: 400) . "\n";
result
2000
1800
1600

Thirty percent of 2000 is 600, but the cap limits the discount to 400.

Key points

  • A default value makes a parameter optional: function tax(float $price, float $rate = 0.18).
  • Named arguments, tax(price: 100, rate: 0.05), let you skip optional parameters and make calls self-explanatory.
  • Type declarations (int, float, string, bool, array, ?string, int|float, mixed) and return types catch wrong values early.
  • ...$values collects any number of arguments into an array; ...$array spreads an array into arguments.

Check yourself

1. What does ?string mean as a parameter type?
2. Which call uses named arguments to set only the rate?
3. What does function total(float ...$prices) receive when called as total(1, 2, 3)?
4. What return type means a function returns nothing?