Type Declarations & Typed Properties
PHP is dynamically typed, but you don't have to fly blind. Type declarations let you state what each parameter, return value, and property should be — and PHP enforces it. Turn on strict_types and a whole class of bugs becomes an immediate, located error.
Learn Type Declarations & Typed Properties in our free PHP course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
1️⃣ Typing Parameters & Returns
Put a type before each parameter, and after the closing parenthesis put : type for the return. PHP enforces these on every call. The scalar types are int , float , string , bool ; plus array , object , class names, and the return-only void . By default PHP runs in coercive mode and will convert a compatible value (note the string "21" below becoming an int).
2️⃣ Strict Mode
Add declare(strict_types=1); as the very first statement of a file to turn off coercion: types must now match exactly, and a mismatch throws a TypeError . This is the recommended default for serious code — it catches wrong types right at the boundary instead of letting a silently-converted value cause a subtle bug deeper in.
3️⃣ Nullable & Union Types
Real values are sometimes "or nothing". A leading ? makes a type nullable : ?string means a string or null (shorthand for string|null ). For multiple real types, PHP 8.0's union syntax lists them with a pipe: int|string .
4️⃣ Typed Properties
Since PHP 7.4 you can type class properties directly. There's one gotcha worth burning into memory: a typed property with no default isn't null — it's uninitialised , and reading it before you assign throws an error. Give it a default, set it in the constructor, or make it nullable if "not set yet" is valid.
Now you try — fill in each ___ using the 👉 hint, then run it and check against the Output panel.
These lines make a strictly-typed file that prints 10 — but they're scrambled. Put them in the order PHP requires.
declare(strict_types=1) must be first ( C ) — it's a fatal error anywhere else. Then define the function: signature ( D ), body ( B ), close ( E ), and finally call it ( A ), which prints 10 .
1. Coercive mode (no strict_types). What prints?
10 — in coercive mode PHP converts the numeric string '9' to the int 9, then adds 1.
2. With declare(strict_types=1) at the top, what happens?
A TypeError is thrown — strict mode refuses to coerce the string '9' into an int.
It throws an Error : "Typed property U::$name must not be accessed before initialization." It has no value yet — not even null.
📋 Quick Reference — Types
No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments.
Practice quiz
In coercive mode (no strict_types), what does double('21') print for function double(int $n): int { return $n * 2; }?
- A TypeError
- 2121
- 42
- 0
Answer: 42. Coercive mode converts the numeric string '21' to int 21, then doubles it to 42.
With declare(strict_types=1), what does calling double('21') do?
- Throws a TypeError
- Returns 42
- Returns '2121'
- Returns null
Answer: Throws a TypeError. Strict mode refuses to coerce a string into an int, so a TypeError is thrown.
Where must declare(strict_types=1); appear?
- Anywhere in the file
- At the end of the file
- Inside every function
- As the very first statement of the file
Answer: As the very first statement of the file. It must be the very first statement; placing it anywhere else is a fatal error.
What does ?string mean as a type?
- An optional argument
- A string or null
- A string only
- A union of string and int
Answer: A string or null. A leading ? makes a type nullable: ?string is shorthand for string|null.
Which type accepts both an int and a string argument?
- int|string
- int&string
- ?int
- int,string
Answer: int|string. Union types (PHP 8.0) list multiple types with a pipe: int|string.
What happens when you read a typed property that has no default before assigning it?
- It returns null
- It returns 0
- An Error: it must not be accessed before initialization
- It returns an empty string
Answer: An Error: it must not be accessed before initialization. A typed property with no default is uninitialised — not null — and reading it before assignment throws an Error.
Even in strict mode, which conversion does PHP still allow for typed arguments?
- Passing a string where an int is expected
- Passing an int where a float is expected (widening)
- Passing an array where a string is expected
- Passing a bool where a string is expected
Answer: Passing an int where a float is expected (widening). The one sanctioned exception is widening an int to a float, because it loses nothing.
What does the void return type mean?
- The function returns null
- The function returns an empty array
- The function never finishes
- The function returns nothing
Answer: The function returns nothing. : void declares that a function returns no value; using return $x; in it is an error.
Which is the correct way to give a nullable typed property a starting value?
- public string $note = null;
- public ?string $note = null;
- public string $note;
- public ?string $note;
Answer: public ?string $note = null;. A nullable property can default to null: public ?string $note = null; — a non-nullable string cannot.
What is the recommended default for serious typed PHP code?
- Avoid type declarations entirely
- Use only union types
- Enable declare(strict_types=1) in every file
- Rely on coercion everywhere
Answer: Enable declare(strict_types=1) in every file. Most teams enable strict types everywhere because catching a TypeError at the boundary beats chasing wrong values.