Type Juggling & Casting
PHP is a weakly typed language, which means it will often convert a value from one type to another automatically, without you asking it to. This automatic conversion is called type juggling. It happens constantly — every time you compare a string to a number, concatenate a number into a string, or use a value in an if condition. Understanding the rules behind it turns what looks like unpredictable behavior into something you can reason about, and it explains why PHP 8 tightened several of these rules compared to earlier versions.
Implicit conversion in arithmetic
When you use an arithmetic operator on a string that "looks like" a number, PHP converts the string to an int or float before doing the math.
Numeric strings in arithmetic
<?php
$a = "10";
$b = "4";
var_dump($a + $b); // int(14) - both strings converted to int
var_dump("10" + 4.5); // float(14.5)
var_dump("10 apples" . " and " . 5 . " oranges");int(14) float(14.5) string(24) "10 apples and 5 oranges"
Note the difference: the + operator triggers numeric conversion, while the . (concatenation) operator triggers the opposite — converting numbers into strings.
Implicit conversion in boolean contexts
Every value can be interpreted as a boolean when used in an if, while, or logical operator. PHP calls a value falsy if it converts to false, and everything else is truthy. The Booleans & Truthiness page covers this in full detail, but the short version is: 0, 0.0, "", "0", empty arrays [], and null are the falsy values; every other value, including the string "0.0", is truthy.
Truthiness in an if condition
<?php
$values = [0, "0", "0.0", "", "false", [], [0]];
foreach ($values as $value) {
echo var_export($value, true) . ' => ' . ($value ? 'truthy' : 'falsy') . "\n";
}0 => falsy '0' => falsy '0.0' => truthy '' => falsy 'false' => truthy array ( ) => falsy array ( 0 => 0, ) => truthy
Explicit casting
Rather than relying on an operator to trigger a conversion, you can force one directly by writing the target type in parentheses in front of a value. This is the clearest way to convert a type when the surrounding code does not make the intent obvious on its own.
Explicit casts
<?php
$raw = "42.9";
var_dump((int) $raw); // int(42) - truncates, does not round
var_dump((float) $raw); // float(42.9)
var_dump((string) 42.9); // string(4) "42.9"
var_dump((bool) ""); // bool(false)
var_dump((array) "hi"); // array(1) { [0]=> string(2) "hi" }int(42)
float(42.9)
string(4) "42.9"
bool(false)
array(1) {
[0]=>
string(2) "hi"
}PHP 8's stricter numeric strings
Before PHP 8.0, a "leading numeric string" like "123abc" was treated leniently: using it in arithmetic silently used the leading 123 and threw away the rest, often without so much as a notice. PHP 8.0 tightened this: a string is only considered a proper numeric string if the entire string (aside from surrounding whitespace) parses as a number. Leading-numeric strings that are not fully numeric now trigger a warning when used in arithmetic, even though they still coerce to their leading numeric portion for backward compatibility.
Leading-numeric strings in PHP 8
<?php
var_dump("123" + 1); // int(124) - fully numeric, no warning
var_dump("123abc" + 1); // int(124) - Warning: A non-well formed numeric value
var_dump("abc" + 1); // TypeError in PHP 8: Unsupported operand typesOpting out with declare(strict_types=1)
By default, PHP applies type juggling to scalar type hints on function parameters and return types too — passing an int where a function expects a string parameter just converts it silently. Adding declare(strict_types=1); as the very first statement in a file disables that coercion for calls made from that file: from then on, scalar type declarations must be matched exactly, or a TypeError is thrown.
strict_types in action
<?php
declare(strict_types=1);
function double(int $n): int
{
return $n * 2;
}
echo double(5); // 10 - exact type, works fine
echo double("5"); // TypeError: Argument #1 ($n) must be of type int, string givendeclare(strict_types=1)must be the first statement in the file, before even a blank line of other code, or PHP raises a fatal error.Strict typing only affects scalar type declarations (int, float, string, bool); it never changes how
+,., orifjuggle types on their own.An
intpassed where afloatparameter is expected is still allowed under strict types, because widening an int to a float loses no information.
From | To | Result |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|