01 · THE IDEAREAD → TRY → LEARN
Why declare types?
A function signature is a small contract. It tells callers what the function accepts and what it promises to give back. Without types, a mistake such as passing an array where a string was expected may travel deep into your program before anything fails. With a type declaration, PHP checks the value when the function is called, and throws a TypeError if the value does not fit.
Type declarations can be placed on function parameters and return values. They can also be placed on class properties (since PHP 7.4) and class constants (since PHP 8.3), but this lesson focuses on functions.
Parameter and return types
You write a parameter type before the variable name, and a return type after the closing parenthesis, following a colon. Common scalar types are int, float, string and bool. You can also use array, class names, interface names, and more.
Be careful with names: boolean and integer are not aliases for bool and int. PHP treats them as class names, which almost never does what you want.
By default, PHP uses coercive typing for scalar declarations. If a numeric string is passed to an int parameter, PHP converts it. The example below calls the same function with an integer and with a numeric string.
function addTax(int $cents, float $rate): int
{
return (int) round($cents * (1 + $rate));
}
echo addTax(1000, 0.2), "\n";
echo addTax("1000", 0.2), "\n";1200 1200
Both calls give the same answer because "1000" is converted to 1000. The return type int also guarantees that the caller receives an integer, which is why the function casts the rounded float explicitly.
Nullable types
Sometimes null is a legitimate value. A single type can be made nullable by prefixing it with a question mark: ?string means exactly the same as string|null. A nullable parameter still has to be supplied unless it has a default value, but it may receive null.
The PHP manual notes that giving a typed parameter a default of null to make it implicitly nullable, as in C $c = null, is deprecated as of PHP 8.4. Write ?C $c = null instead when you want both the nullable type and a default.
The next example accepts ?string, replaces null with a fallback, and then shows what happens when a value of the wrong kind is passed.
function label(?string $name): string
{
return $name ?? 'guest';
}
echo json_encode([label('Ada'), label(null)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
try {
echo label([]);
} catch (TypeError $e) {
echo "TypeError caught\n";
}["Ada","guest"] TypeError caught
An array can never be converted to a string parameter, so PHP throws a TypeError. You can catch it, but usually the better response is to fix the caller.
Strict typing
Coercion is convenient, yet it can hide bugs. You can opt into strict mode for one file by placing declare(strict_types=1); as the very first statement. In strict mode, scalar values must match the declared type exactly. The only exception is that an int is accepted where a float is declared.
Strict mode applies to calls made from the file that declares it, not to functions defined there. It also only concerns scalar types, and calls made from inside built-in functions are not affected.
declare(strict_types=1);
function double(int $n): int
{
return $n * 2;
}
try {
echo double("5");
} catch (TypeError $e) {
echo "strict mode rejected string\n";
}
echo double(5), "\n";strict mode rejected string 10
Common mistakes
- Using
booleanorintegerinstead ofboolorint. - Forgetting that
?intstill allowsnull, so the function body must handle it. - Assuming coercion is harmless: a value may silently change type.
- Declaring a return type and then returning something that cannot be converted to it, which throws a
TypeError.
Exercise contract
Write formatName(?string $first, ?string $last): string. It must join the non-empty name parts with a single space. A part is ignored when it is null or an empty string. If no usable part remains, return Unknown. For example, formatName("Ada", null) returns Ada, and formatName("", "") returns Unknown. The tests check the returned string for five inputs, including null values and empty strings.
Recap
Type declarations make function contracts explicit. Put parameter types before variables and return types after the parameter list. Use ?T when null is allowed. Expect a TypeError when a value cannot satisfy the declaration, and consider strict_types when you want exact scalar matching.
Functions · Types
- Declare parameter and return types
- Recognize nullable values and type errors