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.
🧩 Reorder Challenge
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 .
🧠 Quick Recall — Predict the Output
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.
Common Errors (and the fix)
- "Typed property must not be accessed before initialization" — you read a typed property before assigning it. Set it in the constructor, give a default, or make it nullable.
- "strict_types declaration must be the very first statement" — move declare(strict_types=1); to the top, above everything (even comments are fine, but no code before it).
- "TypeError: ... must be of type int, string given" — a real type mismatch. Pass the right type, or cast deliberately with (int) if conversion is intended.
- "A void function must not return a value" — a : void function used return $x; . Use a bare return; or change the return type.
Pro Tips
- 💡 Put declare(strict_types=1); at the top of every file. It's the single biggest reliability upgrade for typed PHP.
- 💡 Prefer ?Type over Type|null for the common "this or nothing" case — it reads cleaner.
- 💡 Type your properties. They double as documentation and let your editor and tools catch mistakes before runtime.
📋 Quick Reference — Types
Syntax
Example
What It Does
type $param
function f(int $n)
Typed parameter
): type
function f(): string
Return type
: void
function log(): void
Returns nothing
?type
?string
Nullable (type or null)
a|b
int|string
Union of types
public type $p
public float $balance
Typed property
declare(strict_types=1)
declare(strict_types=1);
Turn off coercion (file-wide)
Frequently Asked Questions
Mini-Challenge: Typed Temperature Class
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.
🎉 Lesson Complete!
- ✅ Declare types on parameters, returns, and properties — PHP enforces them
- ✅ declare(strict_types=1); (first line!) turns off silent coercion
- ✅ ?type is nullable; a|b is a union of types
- ✅ A typed property with no default is uninitialised , not null — set it before reading
- ✅ Mismatches throw a TypeError you can catch at the boundary
- ✅ Next lesson: Checkpoint — combine enums, closures, traits, JSON and types in one build
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.
Continue this course
- Previous: Generators (yield)
- Next: Checkpoint: Data & Types