0

Type coercion vs type casting — implicit vs explicit conversion

Beginner5 min read·eng-12-007
interview

Definition

Type coercion is an implicit, automatic conversion PHP performs when an operation requires a type different from the one provided — the runtime decides the target type based on context, and you never wrote a conversion instruction. Type casting is an explicit, programmer-authored conversion using a cast operator ((int), (string), (bool), etc.) that expresses intent clearly in source code. The distinction matters because coercion is invisible and context-dependent, making it a source of subtle bugs; casting is visible and deterministic.

In Practice

php
<?php
// TYPE COERCION — PHP converts automatically, you wrote nothing
// Arithmetic context coerces string to int/float:
$result = "5" + 3;        // 8 (int) — PHP coerced "5" to int 5
$result = "5.5" + 1;      // 6.5 (float)
$result = "5 items" + 1;  // 6 (int) — warning in PHP 8, silently in PHP 7

// Boolean context coerces in conditionals:
if ("") { /* not reached — empty string coerces to false */ }
if ("0") { /* not reached — "0" is falsy in PHP! */ }
if (0) { /* not reached */ }
if ([]) { /* not reached — empty array is falsy */ }
if ("false") { /* IS reached — non-empty non-"0" string is truthy */ }

// Loose comparison (==) coerces before comparing:
var_dump(0 == "foo");   // PHP 7: true (!!), PHP 8: false — changed
var_dump(0 == "");      // PHP 7: true,       PHP 8: false — changed
var_dump("1" == "01");  // true — both coerced to int 1

// TYPE CASTING — explicit, programmer-authored, visible
$str   = "42 items";
$num   = (int) $str;      // 42 — truncates at first non-numeric char
$float = (float) "3.14px"; // 3.14
$bool  = (bool) "";        // false
$arr   = (array) "hello";  // ["hello"]
$obj   = (object) ['a' => 1]; // stdClass with property $a = 1

// Strict mode prevents argument coercion:
declare(strict_types=1);

function double(int $n): int {
    return $n * 2;
}

double(5);      // 10
double("5");    // TypeError in strict mode — no coercion allowed
double(5.9);    // TypeError in strict mode — float not accepted as int

In Laravel, coercion appears at the model layer: Eloquent casts ($casts array) perform explicit, configured casting when you access an attribute. Without a cast, a boolean column stored as 0/1 in SQLite returns a string — a silent type mismatch that PHP coerces silently but that fails strict comparisons.

In Context

Interviews raise this topic when discussing PHP 8 migration, bugs in legacy code, or type safety. The critical historical fact is that PHP 7's loose comparison behavior was a security vulnerability vector: 0 == "admin" was true, meaning hash comparisons with == instead of === could be bypassed. PHP 8 changed this — 0 == "non-numeric-string" is now false. Knowing this shows you track security implications of language changes.

A common misconception is that declare(strict_types=1) makes PHP fully strongly typed. It only affects user-defined function argument coercion within that file — it does not affect arithmetic operations, loose comparisons, or type coercion in internal PHP functions.

Related terms: "type juggling" is the informal name for PHP's implicit coercion behavior. "Type safety" refers to a language design property where type errors are caught at compile time — PHP is not type-safe in this sense; it is type-checked at runtime. "Strict comparison" (===) checks both value and type without coercion and is almost always the correct choice.