Scalar Type Declarations (PHP 7.0)
debt(d5/e5/b5/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan, psalm, and rector — all specialist static analysis tools. Missing type declarations or coercion bugs won't be caught by a compiler or a default linter; they require running PHPStan/Psalm configured at an appropriate level. Slightly elevated from d5 because the coercion issue is also silent at runtime (no error, just wrong behaviour), but the tooling is specialist-tier so d5 fits best.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says: add scalar type hints to all function parameters and return types, add declare(strict_types=1) at the top of each file, then run PHPStan. This is a file-by-file sweep across the codebase — not a single-line patch and not merely one component, but also not a full architectural rework. e5 is the right anchor.
Closest to 'persistent productivity tax' (b5). The applies_to covers all PHP contexts (web, cli, queue-worker), meaning every function and method signature is touched by this choice. Missing or incorrect type declarations impose an ongoing analysis gap — every future developer must remember to add strict_types per-file and annotate types properly. It doesn't redefine the system's shape (b9) but it is a pervasive, recurring cost across many work streams (b5).
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception field is explicit: developers expect scalar type declarations to enforce types the way they do in most statically-typed languages, but without declare(strict_types=1) PHP silently coerces values. This directly contradicts the experience of Java, C#, TypeScript, and even PHP's own stricter mode — a competent developer from any of those languages will confidently assume type enforcement and be wrong. The common_mistakes list confirms this is the dominant failure mode.
TL;DR
Explanation
PHP 7.0 (December 2015) added scalar type hints: int, float, string, bool. With declare(strict_types=1): strict enforcement — wrong type throws TypeError. Without it: PHP coerces where possible ('5' → 5). Return types also added: function add(int $a, int $b): int. This enabled PHPStan, Psalm, and IDE analysis to verify type contracts. Previously only class/interface names and array/callable were valid hints. PHP 7.1 added nullable types (?string), PHP 7.1 added void return. PHP 8.0 added union types (int|string), PHP 8.1 added never.
Common Misconception
Why It Matters
Common Mistakes
- Not using declare(strict_types=1) — coercion hides type bugs.
- Forgetting to add return types — functions without return types can't be fully analysed.
- Using mixed instead of proper union types — loses all type safety.
Code Examples
// PHP 5 — no type hints:
function add($a, $b) {
return $a + $b; // What if strings are passed?
}
<?php declare(strict_types=1);
function add(int $a, int $b): int {
return $a + $b;
}
function greet(?string $name): string {
return 'Hello, ' . ($name ?? 'World');
}