0

PHP type coercion in strict mode vs non-strict — full breakdown

Advanced5 min read·eng-09-007
interview

Concept

PHP's type coercion behaves very differently depending on whether declare(strict_types=1) is present at the top of the calling file.

Non-strict mode (default, no declaration):

  • PHP coerces scalar types automatically on function calls.
  • int → float: Always safe.
  • float → int: Truncates decimal part (not rounds). 3.9 → 3.
  • string → int/float: If the string starts with a number, extracts it. "42abc" → 42, "abc" → 0.
  • bool → int: true → 1, false → 0.
  • null → int/float/string/bool: null → 0, null → "", null → false.
  • int/float → string: Converts to string representation.

Strict mode (declare(strict_types=1) in the CALLING file):

  • Only exact type accepted (with one exception: int IS accepted where float is expected).
  • Passing "42" where int is expected → TypeError.
  • Passing 3.9 where int is expected → TypeError.
  • The declaration affects calls FROM that file, not the function being called.

Important: strict_types applies to the FILE that makes the call, not the file that defines the function. A function defined without strict_types can still be called strictly from a file that HAS strict_types=1.

Union types (PHP 8.0+): int|string accepts either type. More explicit than coercion.

declare(strict_types=1) must be the very first statement in the file — before any code, before namespace, after only <?php and optional BOM.

settype() / (int) / intval(): Explicit coercion in PHP — always works regardless of strict mode (these are type casts, not type declarations).

Code Example

php
<?php
// ============================================================
// NON-STRICT MODE — default PHP behavior
// ============================================================
function addNumbers(int $a, int $b): int
{
    return $a + $b;
}

// Without strict_types:
addNumbers(1, 2);        // 3 — exact match, fine
addNumbers(1.9, 2.1);    // 3 — floats truncated to 1 and 2
addNumbers("5", "3");    // 8 — strings coerced to ints
addNumbers("5abc", "3"); // 8 — "5abc" → 5 (with E_DEPRECATED in PHP 8.1)

// String to number coercion
$x = "10" + 5;     // 15 — PHP coerces "10" to 10
$y = "10abc" + 5;  // 15 — numeric string prefix extracted
$z = "abc" + 5;    // 5  — non-numeric string → 0

// Null coercion
function greet(?string $name): string
{
    return "Hello " . ($name ?? 'stranger');
}
greet(null);  // "Hello stranger"

// Bool to int
var_dump((int) true);   // 1
var_dump((int) false);  // 0
var_dump((bool) 0);     // false
var_dump((bool) "");    // false
var_dump((bool) "0");   // false — only "0" is falsy string
var_dump((bool) "false"); // TRUE — non-empty, non-"0" string is truthy!