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

Type Safety in PHP (strict_types & Static Analysis)

quality PHP 7.4+ Intermediate

Also Known As

type checking strict types type enforcement

TL;DR

Combining strict_types=1, typed properties, return types, union types, and PHPStan/Psalm to catch type errors at analysis time rather than runtime.

Explanation

PHP's type system has evolved substantially: scalar type declarations (PHP 7.0), return types (7.0), nullable types (7.1), typed class properties (7.4), union types (8.0), intersection types (8.1), and DNF types (8.2). Declaring strict_types=1 at the top of a file makes PHP enforce declared types strictly — no silent coercions. But strict_types only applies to function calls within that file. The real force multiplier is static analysis: PHPStan and Psalm infer types through the code graph, catching: passing null where not nullable, incorrect return types, impossible conditions, and missing match arms. Aim for PHPStan level 6+ and full property/return type coverage. Use /** @var Type */ docblocks only where inference is insufficient.

Common Misconception

declare(strict_types=1) makes PHP fully type-safe. Strict types enforce scalar type coercion at call boundaries in that file only — it does not affect calls from other files without strict mode, and does not prevent null or wrong-class objects from passing typed parameters.

Why It Matters

Type safety enforced by PHP's type declarations and strict_types catches a whole category of bugs at development time rather than production runtime — wrong argument types become errors, not silent corruptions.

Common Mistakes

  • Not declaring return types — the method contract is implicit and callers cannot trust the type.
  • Using mixed or omitting types on internal methods — type safety degrades from the inside out.
  • Not enabling strict_types=1 — PHP silently coerces types without it, hiding mismatches.
  • Relying on PHPDoc @return annotations for type safety — they are not enforced at runtime.

Code Examples

✗ Vulnerable
// No type declarations — silent type coercion hides bugs:
function calculateDiscount($price, $percent) {
    return $price * ($percent / 100); // '10' * (0.1) = 1.0 — works, but by accident
}
calculateDiscount('ten', '20%'); // No error, returns 0

// With types:
function calculateDiscount(float $price, float $percent): float { /* ... */ }
✓ Fixed
<?php declare(strict_types=1);

class Money {
    public function __construct(
        public readonly int $amount,
        public readonly string $currency,
    ) {}

    public function add(Money $other): Money {
        if ($this->currency !== $other->currency) {
            throw new CurrencyMismatchException();
        }
        return new Money($this->amount + $other->amount, $this->currency);
    }
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 99
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 2 pings M 0 pings T 0 pings W 1 ping T 1 ping F 1 ping S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T
Perplexity 1
No pings yesterday
Perplexity 41 ChatGPT 15 Amazonbot 14 Google 6 Unknown AI 3 Majestic 2 Ahrefs 1
crawler 81 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: High
⚡ Quick Fix
Work towards PHPStan level 8 incrementally — fix one level per sprint, starting from level 3 which catches the most impactful bugs without too many false positives
📦 Applies To
PHP 7.4+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
PHPStan below level 5; mixed types everywhere; functions without return types; type errors only caught at runtime
Auto-detectable: ✓ Yes phpstan psalm rector
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: File
CWE-704

✓ schema.org compliant