01 · THE IDEAREAD → TRY → LEARN
Why defaults exist
Many functions have a normal way to behave and a few settings that only occasionally change. A default value lets the function declare that normal behavior in its signature. Callers supply only what differs, and the function body always receives a complete set of values.
You declare a default with an assignment after the parameter: string $container = "bowl". The default is used only when the caller leaves that argument out entirely.
A first example
The function below has one required parameter and one optional one. Required parameters come first, because an optional parameter in front of a required one can never really be omitted.
function makeYogurt(string $flavour, string $container = "bowl"): string {
return "Making a $container of $flavour yogurt.";
}
echo makeYogurt("raspberry"), "\n";
echo makeYogurt("mango", "cup"), "\n";Making a bowl of raspberry yogurt. Making a cup of mango yogurt.
The first call omits the second argument, so $container becomes "bowl". The second call replaces it with "cup".
A default must be a constant expression. Scalars, arrays, null and, since PHP 8.1, new ClassName() are all allowed. A variable or an ordinary function call is not.
Defaults go last
Put required parameters before optional ones. Declaring a required parameter after an optional one is deprecated, because the earlier default can never be used. The usual fix is to drop that default. A related PHP 8.4 point: a signature such as Type $x = null relies on implicit nullability, which is deprecated as of 8.4. Write the nullable type explicitly instead, for example ?string $x = null.
Named arguments
Positional calls become hard to read once a function has several optional parameters. If you only want to change the third one, you would have to repeat the first two defaults. Named arguments solve this: write the parameter name, a colon, then the value.
function makeYogurt(string $container = "bowl", string $flavour = "raspberry", string $style = "Greek"): string {
return "Making a $container of $flavour $style yogurt.";
}
echo makeYogurt(style: "natural"), "\n";
echo makeYogurt(flavour: "mango", container: "cup"), "\n";Making a bowl of raspberry natural yogurt. Making a cup of mango Greek yogurt.
The order of named arguments does not matter, and skipped parameters keep their defaults. You can mix styles, but positional arguments must come first and named ones after them. Naming the same parameter twice, or naming one that a positional argument already filled, throws an Error. The name must be written literally; you cannot compute it from a variable.
Null is not "missing"
A very common surprise: passing null does not select the default. null is a real value, and the parameter receives it.
function label(?string $text = "untitled"): string {
return $text ?? "(null)";
}
echo json_encode([label(), label(null), label("Report")]), "\n";["untitled","(null)","Report"]
Only the first call uses "untitled". If you want null to mean "use the normal behavior", declare the default as null with a nullable type and resolve it inside the body, for example with $value ??= "fallback". This also works around the constant-expression rule when the real default needs computing.
Practical guidance
- Choose defaults that are safe and common, not clever.
- Keep the number of optional parameters small. Past three or four, named calls make call sites much clearer.
- Use named arguments for booleans and other values whose meaning is not obvious at the call site.
- Remember that parameter names become part of your public interface once callers use them by name.
Exercise contract
Write greet(string $name, ?string $greeting = null, string $punctuation = "!"): string.
- The result is the greeting, a comma and a space, the name, then the punctuation.
- If
$greetingisnull, use"Hello". - If
$nameis an empty string, use"friend"instead. - An empty punctuation string is allowed and adds nothing.
For example, greet("Ana") returns "Hello, Ana!", and greet("Ana", "Hi", "") returns "Hi, Ana". The tests call your function positionally, so make sure the optional parameters really are optional.
Recap
Defaults make trailing parameters optional and are used only when the argument is omitted. Keep required parameters first and write nullable types explicitly. Passing null is not the same as omitting an argument. Named arguments let you skip any optional parameter and make calls self-documenting.
Functions
- Provide useful parameter defaults
- Call a function with named arguments