← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Nullable Types (?Type)

PHP PHP 7.1+ Beginner
debt(d5/e3/b3/t5)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan, psalm, and rector — all specialist static analysis tools. Common misuse (e.g. missing ?Type annotation, or using mixed to hide nullability) won't surface at compile time or via default linters, but these dedicated tools catch it reliably when configured.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes adding or removing ?Type annotations on parameters and return types, which is a localised pattern-replacement. Rector can automate many cases, but the developer must also audit call sites and add null-checks or null-safe operator usage — slightly more than a one-liner but contained within one component.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). Nullable types apply across web, cli, and queue-worker contexts, but the burden is per-function/per-class boundary. Overuse of ?Type (a noted common mistake) adds review overhead in the affected component, but it doesn't reshape the entire codebase or impose a strong gravitational pull beyond the functions where it's declared.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap' (t5). The misconception field identifies the canonical gotcha: developers often assume nullable types encourage passing null everywhere, when the intent is the opposite — they make nullability explicit and opt-in. Additional common mistakes (forgetting explicit return null, not using ?-> on nullable return values, overusing ?Type to avoid validation) are documented gotchas that most PHP developers eventually encounter, matching the t5 anchor.

About DEBT scoring →

Also Known As

nullable type ?string PHP nullable

TL;DR

Declaring a type as ?Type allows either a value of that type or null — shorthand for Type|null.

Explanation

Nullable types (PHP 7.1+) prefix a type declaration with ? to indicate the value may be null in addition to the declared type. function find(?int $id): ?User accepts null for $id and may return a User or null. This is equivalent to the union type int|null and User|null introduced in PHP 8.0. Nullable types made it practical to type-hint optional parameters and nullable return values without resorting to mixed. Combine with the null coalescing operator (??) and nullsafe operator (?->) for clean null handling.

Common Misconception

Nullable types encourage passing null everywhere. They do the opposite — they make nullability explicit and opt-in. A function typed string cannot receive null; only ?string can. This forces developers to handle null intentionally rather than accidentally.

Why It Matters

PHP's nullable type syntax (?Type) makes null a documented, type-checked part of the contract — without it, null silently passes through typed parameters causing downstream failures.

Common Mistakes

  • Using ?Type when null should actually be forbidden — nullable types are sometimes overused to avoid validation.
  • Forgetting that nullable return types require explicit return null statements — returning nothing returns null implicitly but ?Type requires it to be intentional.
  • Not using the nullsafe operator (?->) when chaining calls on nullable return values.
  • Returning null from constructors — constructors cannot be nullable; throw an exception instead.

Code Examples

✗ Vulnerable
// Nullable parameter used where null should be invalid:
function setAge(?int $age): void {
    $this->age = $age; // Allows null — but a person must have an age
}

// If null means 'unknown', model it explicitly:
function setAge(int $age): void { // Enforce valid age
    if ($age < 0 || $age > 150) throw new InvalidArgumentException();
    $this->age = $age;
}
✓ Fixed
// ?Type is shorthand for Type|null
function findUser(int $id): ?User {
    return $this->db->find($id); // null if not found
}

// Nullable parameter with default
function greet(?string $name = null): string {
    return 'Hello, ' . ($name ?? 'Guest');
}

// Typed nullable property (PHP 7.4+)
class Order {
    public ?\DateTimeImmutable $shippedAt = null; // not shipped yet
}

// PHP 8.0+ — use union type for explicit null
function process(int|null $value): void {}
// Equivalent to: function process(?int $value): void {}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 54
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 3 pings F 2 pings S 3 pings S 1 ping M 1 ping T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W
No pings yet today
PetalBot 2
Scrapy 12 Amazonbot 9 Perplexity 6 Ahrefs 4 SEMrush 4 ChatGPT 3 Google 3 Unknown AI 2 Claude 2 PetalBot 2 Bing 1
crawler 45 crawler_json 3
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Use ?string for optional parameters and return types — but consider whether null is the right signal; sometimes an empty collection, a NullObject, or an Optional-style type communicates intent better
📦 Applies To
PHP 7.1+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Function returning null for 'not found' without nullable return type; mixed return type hiding nullability; getUser() returning null without ?User annotation
Auto-detectable: ✓ Yes phpstan psalm rector
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✓ Auto-fixable Fix: Low Context: Function


✓ schema.org compliant