Type Casting in PHP
debt(d5/e1/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpstan, psalm, and php-cs-fixer — all specialist static-analysis tools. The code_pattern notes implicit coercion without strict_types=1 and unnecessary casting, which these tools flag but a default linter or compiler would not catch. Misuse is silent at runtime until edge-case inputs arrive.
Closest to 'one-line patch or single-call swap' (e1). The quick_fix is a direct substitution: swap (int) for filter_var(), add strict_types=1, or replace an implicit coercion with an explicit cast. Each fix is a single-call or single-line change with no structural impact.
Closest to 'localised tax' (b3). Casting choices are scoped to individual expressions or functions. While the tag 'type-system' and applies_to covering all contexts (web, cli, queue-worker) give it some breadth, the impact is localised — a wrong cast in one place rarely forces changes elsewhere across the codebase.
Closest to 'serious trap' (t7). The misconception field documents that (int) and intval() behave differently on objects, and common_mistakes reveal multiple non-obvious behaviours: '0' is falsy, (int)'123abc' silently truncates, (array)null vs (array)$object produce different structures, and float-to-int truncates rather than rounds. These contradict reasonable developer intuitions about type conversion, particularly coming from other languages.
Also Known As
TL;DR
Explanation
PHP supports explicit casting with (int), (bool), (float), (string), (array), (object), and (unset) (removed in PHP 8.0). Casting rules have edge cases: (int)'10abc' === 10, (bool)'' === false, (bool)'0' === false, (array)null === [], (array)'hello' === ['hello']. For integers, intval() allows a base parameter. For security-sensitive conversions, prefer intval() or settype() over casts — the intent is clearer and linting tools flag misuse more reliably. In PHP 8.0+ with strict_types, casting becomes less necessary as type errors are thrown for mismatched arguments.
Watch Out
Common Misconception
Why It Matters
Common Mistakes
- (bool)'0' is false — the string '0' is the only non-empty string PHP treats as falsy.
- (int)'123abc' returns 123 silently — use filter_var() with FILTER_VALIDATE_INT for actual validation.
- (array)null returns [] but (array)$object returns an array of properties — different behaviours for different types.
- Casting floats to int truncates rather than rounds — (int)4.9 is 4, not 5.
Code Examples
// Silent data corruption:
$val = (int)'12.5kg'; // Returns 12 — no error, 'kg' silently dropped
$flag = (bool)'0'; // Returns false — '0' is the only falsy non-empty string
$arr = (array)null; // Returns [] — not an error
// '0' trap:
if ((bool)$_GET['active']) {} // ?active=0 evaluates to false unexpectedly
// Explicit casts — prefer over implicit coercion
\$id = (int) \$_GET['id']; // '42abc' → 42, 'abc' → 0
\$price = (float) \$_POST['price'];
\$flag = (bool) \$value;
\$str = (string) \$object; // calls __toString()
\$arr = (array) \$object; // public properties as array
// intval() with base
\$oct = intval('0777', 8); // 511
\$hex = intval('FF', 16); // 255
// settype() — mutates the variable
settype(\$value, 'integer');
// Falsy values in PHP — know them
// false, 0, 0.0, '0', '', '0.0', [], null → all falsy
// '00', '0.0', ' ' → TRUTHY (non-empty, non-'0' strings)
var_dump((bool)'00'); // true — common surprise