Lesson 14 of 100
Types12 min5 checksPHP 8.5

Type Declarations in PHP 8.4

Learn how parameter and return type declarations describe a function's contract, how nullable types work, and when PHP throws a TypeError.

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.

Example
<?php
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";
Output
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.

Example
<?php
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";
}
Output
["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.

Example
<?php
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";
Output
strict mode rejected string
10

Common mistakes

  • Using boolean or integer instead of bool or int.
  • Forgetting that ?int still allows null, 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.

Before you start

Functions · Types

You’ll practice
  • Declare parameter and return types
  • Recognize nullable values and type errors
Your task

Make formatName() pass all 5 checks. Run your code as often as you like, then check your answer.

exercise.phpSaved in this browserPHP 8.5
CONSOLE & CHECKS● Ready

Ready when you are

Your output will appear here.
Make it work. Then make it pass.

PHP loads on your first run. Each check starts fresh. Your code stays in this browser; clearing site data removes your progress. A check or the task looks wrong? Report a problem with this exercise.